Why and how do we redirect debug statements?

I want to know why he prefers to redirect debug statements to stderr, as is done here:

#ifdef DEBUG_TEST #define DEBUG_TEST 1 #else #define DEBUG_TEST 0 #endif #define DEBUG_PRINT(fmt, ...) \ do { if (DEBUG_TEST) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0) 

Also: how can we redirect these debug statements to a separate log file with a timestamp in that file? I want to do this using a macro in my code.

Platform: Linux, gcc compiler

+4
source share
4 answers

I can give you two examples of why you do this: then you could easily redirect standard output to a file while storing the standard error in your terminal (and this looks like what you want to do in your second question), your tool can highlight Messages sent to stderr, making it easy to find them right away.

You can use the command line version to redirect stderr, as thesamet suggests. To get the timestamp in the file name, you can do something like this when starting your program:

 ./program 2>"logfile-`date`.txt" 

If you want to do this in the program itself, one way is to simply use fopen to open another file and write to it. The following is a complete working example:

 #include <time.h> #include <stdlib.h> #include <stdio.h> #include <stdbool.h> #define DEBUG_TEST true FILE *debug_file; #define DEBUG_PRINT(fmt, ...) \ do { if (DEBUG_TEST) fprintf(debug_file, fmt, ##__VA_ARGS__); } while (false); int main() { time_t timestamp = time(NULL); char * s = malloc(snprintf(NULL, 0, "debug-%d.txt", timestamp)); sprintf(s, "debug-%d.txt", timestamp); debug_file=fopen(s, "w"); DEBUG_PRINT("YEAH\n"); fclose(debug_file); return EXIT_SUCCESS; } 
+2
source

The advantage of using stderr over stdout is that if you redirect output to a file or stream it (using a pipe) to another process, debugging messages do not interfere.

If you want to redirect stderr to a file on Unix, you can run your program as follows:

 ./program 2>logfile 
+3
source

One of the reasons you are reporting debugging information to stderr rather than stdout is because stdout can be piped and your diagnostics will go with the actual data, confusing the subsequent pipelines.

If you want to redirect the output or add timestamps (or PID or any other information), do not use fprintf() directly. Call the function of your own developer, which deals with the information that you want, as you want.

So your macro could be:

 extern void dbg_print(const char *fmt, ...); #define DEBUG_PRINT(fmt, ...) \ do { if (DEBUG_TEST) dbg_print(fmt, __VA_ARGS__); } while (0) 

Or:

 extern void dbg_print(const char *func, const char *file, int line, const char *fmt, ...); #define DEBUG_PRINT(fmt, ...) \ do { if (DEBUG_TEST) dbg_print(__func__, __FILE__, __LINE__, fmt, __VA_ARGS__); } while (0) 

This includes the function name, file name, and line number in the information.

For example, I have a moderately complex package that does this. One of the main internal procedures:

 /* err_stdio - report error via stdio */ static void err_stdio(FILE *fp, int flags, int errnum, const char *format, va_list args) { if ((flags & ERR_NOARG0) == 0) fprintf(fp, "%s: ", arg0); if (flags & ERR_STAMP) { char timbuf[32]; fprintf(fp, "%s - ", err_time(timbuf, sizeof(timbuf))); } if (flags & ERR_PID) fprintf(fp, "pid=%d: ", (int)getpid()); vfprintf(fp, format, args); if (flags & ERR_ERRNO) fprintf(fp, "error (%d) %s\n", errnum, strerror(errnum)); } 

Debug wrappers can call this function with the appropriate flags and generate the desired result. Other parts of the system control the file stream used ( stderr by default, but there is a function to redirect output to any other stream), etc.

If you restrict yourself using fprintf() directly in the debug macro, you are stuck with what fprintf() can do or recompile everything.

See also my answer to 'C # define macro for debug printing' for more information on debugging macros and how to use them (although it looks like this, I took a lot of what I say there on board already).

+1
source

Sorry if I'm wrong, but nobody seems to mention buffering.

By default, stdout is a string buffer on most platforms, and stderr does not load. This basically means that by default, entries in stdout are written to memory and written to the file or console in chunks, because the output character output by character is slooooow.

If you are debugging, you do not want the message to appear much later, then you really mean to print it (or even potentially never print if your program crashes or gets stuck in an endless loop (this can really mess you up when you think that it is looping or falling in the wrong place), and you usually don’t mind hitting the speed.In theory, this may matter due to synchronization and synchronization errors, but in any case it is difficult to catch / debug.

TL DR when debugging printing on stderr is not stdout (other people may suggest logging to a file instead and allowing such runtime parameters as enabling / disabling the print file, style, threshold, etc.).

+1
source

Source: https://habr.com/ru/post/1388558/


All Articles