0

So I'm writing a program that is suppose to run forever (client server stuff) in C, and I'm writing to a log. I am using fopen and fprintf to be able to write to the file. My problem is that since the program is suppose to run forever, there really is no point where I can put a fclose. And when I Ctrl+C to stop the process, and the log file, it shows nothing? I want to use fprintf because it allows me to have formatted strings, is there a way for me to log my output while still having formatted strings?

AusCBloke
  • 18,014
  • 6
  • 40
  • 44
user1289479
  • 291
  • 4
  • 16

4 Answers4

4

What's happening is that the output is being buffered and when the program is killed, the buffer is never flushed to disk. You can either periodically flush the buffer (fflush), or you can try to capture the kill signal. Specifically, Control + C sends the SIGINT signal, so you'd need to register a handler for that.

As to minimize potential buffer loss, I would probably use both strategies.

How can I catch a ctrl-c event? (C++)

Edit: As Adam said, you can also just open and close the file when necessary, but depending on how frequently you're writing, you may want to keep the file open in which case my answer would apply.

Community
  • 1
  • 1
Corbin
  • 33,060
  • 6
  • 68
  • 78
  • I am actually writing pretty frequently, which is why I didn't want to go with the 'open and close each time' method, thanks for telling me what is actually going on. I'll try both methods – user1289479 Mar 24 '12 at 03:39
  • 1
    If you just do periodic flushing, then you can potentially lose data is the program goes down before the next flush. If you try to catch signals, then you can better prevent that, and that's why both is ideal. If you're not particularly concerned with IO performance, you could just fflush after every write. Depending on how aggressively the kernel and physical disk cache, fflush after every write may actually have a very small performance impact. – Corbin Mar 24 '12 at 03:41
1

Each time you want to write a log message, open the file in append mode, print your text to the end of the file, and then close it.

Adam Liss
  • 47,594
  • 12
  • 108
  • 150
1

setbuf(), setvbuf(), or fflush(), - and trap SIGINT or what ever is appropriate relating to your system.


I.e.

#include <stdio.h>
#include <unistd.h>  /* for sleep() in this example */

int main(void)
{
    FILE *fh;
    char *fn = "main.log";
    int i;

    if ((fh = fopen(fn, "w")) ==  NULL) {
        fprintf(stderr,
            "Unable to open file %s\n", fn);
        return 1;
    }

    setbuf(fh, NULL); /* Turns buffering completely off */

    for (i = 1; ; ++i) {
        fprintf(fh, "%d ok ", i);
        if (!(i%120))
            fprintf(fh, "\n");
        sleep(1);
    }

    fclose(fh);

    return 0;
}

in other console :

$ tail -f main.log

Yield: 1 ok 2 ok 3 ok 4 ok 5 ok 6 ok ^C

Or fflush(fh) when you want to flush write buffer.

stdio.h:>


int setvbuf(FILE* stream, char* buf, int mode, size_t size);
        Controls buffering for stream stream. mode is _IOFBF for full buffering, _IOLBF for line buffering, _IONBF for no buffering. Non-null buf specifies buffer of size size to be used; otherwise, a buffer is allocated. Returns non-zero on error. Call must be before any other operation on stream.


void setbuf(FILE* stream, char* buf);
        Controls buffering for stream stream. For null buf, turns off buffering, otherwise equivalent to (void)setvbuf(stream, buf, _IOFBF, BUFSIZ).


int fflush(FILE* stream);
        Flushes stream stream and returns zero on success or EOF on error. Effect undefined for input stream. fflush(NULL) flushes all output streams.

Morpfh
  • 4,033
  • 18
  • 26
0

I'd go with Corbin's answer, but you asked if there's another way to get formatted output.

There is: you could use sprintf() into a char buffer and then use unbuffered open/write/close I/O.

But, don't do that. Keep using fopen() and co., and catch the SIGINT.

blueshift
  • 6,742
  • 2
  • 39
  • 63