C log file implementation

Log files are very useful when you develop programs. Here, we see some samples.

Log file implementation example

To log a message from multiple source files in a C program, you can create a header file that contains function declarations and a source file that defines the logging function.

Here’s an example: [log.h]

#ifndef LOG_H
#define LOG_H

void log_msg(const char *msg);

#endif

Source file : [log.c]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "log.h"

#define LOG_MAX_SIZE 15728640 // 15MB

static FILE *log_file = NULL;
static char *log_filename = NULL;

static void rotate_log() {
    if (log_file != NULL) {
        fclose(log_file);
    }

    // Rename current log file with timestamp
    time_t now = time(NULL);
    char timestamp[20];
    strftime(timestamp, 20, "%Y%m%d%H%M%S", localtime(&now));
    char *new_log_filename = malloc(strlen(log_filename) + strlen(timestamp) + 2);
    sprintf(new_log_filename, "%s.%s", log_filename, timestamp);
    rename(log_filename, new_log_filename);
    free(new_log_filename);

    // Create new log file
    log_file = fopen(log_filename, "w");
}

void log_msg(const char *msg) {
    if (log_file == NULL) {
        return;
    }

    // Check log file size
    fseek(log_file, 0, SEEK_END);
    long log_size = ftell(log_file);
    if (log_size >= LOG_MAX_SIZE) {
        rotate_log();
    }

    // Write message to log file
    time_t now = time(NULL);
    char timestamp[20];
    strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
    fprintf(log_file, "%s %s\n", timestamp, msg);
}

void open_log(const char *filename) {
    log_filename = strdup(filename);
    log_file = fopen(log_filename, "w");
}

void close_log() {
    if (log_file != NULL) {
        fclose(log_file);
        log_file = NULL;
    }
    free(log_filename);
    log_filename = NULL;
}

The log.h header file declares the log_msg() function, which can be called from other source files. The log.c source file defines the log_msg() function, along with any additional functions and variables needed to implement the logging functionality.

We declare the variables as ‘static’ so that they stay till the life of the program.

To use the logging function in another source file, simply include the log.h header file and call log_msg() as needed:

main file : [main.c]

#include "log.h"

int main() {
    open_log("logfile.txt");

    log_msg("Starting program");

    // ...

    log_msg("Program finished");

    close_log();

    return 0;
}

Note that you need to call open_log() before logging any messages, and close_log() when you are finished logging messages. Also note that log.c needs to be compiled and linked with any source files that call log_msg().

Explanation

This implementation uses the LOG_MAX_SIZE constant to define the maximum size of each log file. When log_msg() is called, it first checks the current size of the log file. If it is greater than or equal to LOG_MAX_SIZE, it calls rotate_log() to rename the current log file with a timestamp and create a new log file.

rotate_log() first closes the current log file (if it is open), then renames the file using the current log filename and a timestamp. Finally, it creates a new log file with the same filename as the original log file.

open_log() opens the log file with the given filename for writing. close_log() closes the log file (if it is open) and frees the memory used by log_filename.

Note that this implementation does not include any error checking for file I/O or memory allocation. Depending on your use case, you may need to add additional error handling code.

Additional notes :

In C, the rename() function is used to rename a file. It takes two arguments:

int rename(const char *oldname, const char *newname);
  • oldname: The current name of the file to be renamed.
  • newname: The new name to give to the file.

The rename() function returns 0 on success, and -1 on failure. Here’s an example usage of the rename() function.

#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *oldname = "oldfile.txt";
    const char *newname = "newfile.txt";

    if (rename(oldname, newname) != 0) {
        fprintf(stderr, "Failed to rename file\n");
        exit(EXIT_FAILURE);
    }

    printf("File renamed successfully\n");

    return 0;
}

In this example, the rename() function is used to rename the file “oldfile.txt” to “newfile.txt”. If the function returns -1, indicating a failure to rename the file, an error message is printed to the standard error stream and the program exits with a failure status code. Otherwise, a success message is printed to the standard output stream.

Creating a rotating log after specified size

Here’s an example C program that creates a rotating log file every time the current log file reaches 15MB:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_LOG_SIZE 15728640 // 15MB in bytes

int main() {
    FILE *fp;
    char filename[256];
    char timestamp[20];
    time_t current_time;
    int log_count = 1;
    long log_size = 0;
    char buffer[1024];

    while (1) {
        // Get the current time
        current_time = time(NULL);

        // Format the timestamp string
        strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", localtime(&current_time));

        // Create the filename
        sprintf(filename, "log_%d_%s.txt", log_count, timestamp);

        // Open the log file
        fp = fopen(filename, "a");

        if (fp == NULL) {
            printf("Error opening log file %s\n", filename);
            return 1;
        }

        // Write to the log file
        while (log_size < MAX_LOG_SIZE) {
            fprintf(fp, "Log message\n");
            fflush(fp);
            log_size = ftell(fp);
        }

        // Close the log file
        fclose(fp);

        // Increment the log count and reset the log size
        log_count++;
        log_size = 0;
    }

    return 0;
}

In this example, the program creates a new log file every time the current log file reaches 15MB. The program uses the standard C library functions time(), strftime(), sprintf(), fopen(), fprintf(), fflush(), ftell(), and fclose() to achieve this.

The program uses a while loop to continuously write to the log file. Inside the loop, the program first gets the current time using time() and formats it as a string using strftime(). The program then creates a filename based on the current log count and the current timestamp using sprintf().

The program then opens the log file in append mode using fopen(). Inside a nested while loop, the program repeatedly writes to the log file using fprintf() and flushes the output using fflush(). The program checks the current size of the log file using ftell() and exits the nested loop when the log file size reaches 15MB.

Finally, the program closes the log file using fclose() and increments the log count. The program then resets the log size to 0 and starts the loop again with a new log file.