00001 #include "copyright.h" 00002 /*============================================================================*/ 00003 /*! \file ath_log.c 00004 * \brief Functions for controlling output to stderr and stdout. 00005 * 00006 * PURPOSE: Functions for controlling output to stderr and stdout. On many 00007 * machines, output to stderr and stdout does not scale well (to 10^{4-5} 00008 * processors). However, having output from all MPI processes can be useful 00009 * for debugging. Thus, some kind of runtime control that allows output to 00010 * stderr and stdout be turned off for production runs, or redirected to 00011 * files for debugging, is very helpful. 00012 * 00013 * CONTAINS PUBLIC FUNCTIONS: 00014 * - ath_log_out_open() - opens out log file 00015 * - ath_log_err_open() - opens err log file 00016 * - ath_log_set_level() - sets logging level from input arguments 00017 * - ath_log_open() - calls output/error log file open if lazy == 0 00018 * - ath_log_close() - closes output/error log file close 00019 * - athout_fp() - returns pointer to out logfile 00020 * - atherr_fp() - returns pointer to err logfile 00021 * - ath_flush_out() - flushes out log file 00022 * - ath_flush_err() - flushes err log file 00023 * - ath_perr() - writes to err file 00024 * - ath_pout() - writes to out file */ 00025 /*============================================================================*/ 00026 00027 #include <stdarg.h> 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 #include <sys/types.h> 00032 #include <sys/stat.h> 00033 #include "prototypes.h" 00034 00035 /* output and error log levels */ 00036 static int out_level = 0, err_level = 0; 00037 00038 /* Simulation output and error file pointers */ 00039 static FILE *ath_fp_out = NULL, *ath_fp_err = NULL; 00040 00041 /* Simulation output and error log file names */ 00042 static char *out_fname = NULL, *err_fname = NULL; 00043 00044 /* Logical flags indicating that the files need to be opened */ 00045 static int open_out_flag = 0, open_err_flag = 0; 00046 00047 /* Mode for which the log files are opened, e.g. "a" or "w" */ 00048 static char log_mode[2] = "w"; 00049 00050 00051 /*----------------------------------------------------------------------------*/ 00052 /*! \fn static int ath_log_out_open(void) 00053 * \brief Opens output log file (containing output to stdout). 00054 */ 00055 static int ath_log_out_open(void) 00056 { 00057 int iExist=1; 00058 struct stat statinfo; 00059 00060 open_out_flag = 0; /* zero the flag to open the file, only 1 try if we fail */ 00061 00062 if(log_mode[0] == 'a') 00063 iExist = stat(out_fname, &statinfo); 00064 00065 /* open the ath_fp_out file pointer */ 00066 if((ath_fp_out = fopen(out_fname, log_mode)) == NULL){ 00067 fprintf(stderr,"[ath_log_out_open]: Failed to open ath_fp_out as \"%s\"\n", 00068 out_fname); 00069 return 1; 00070 } 00071 00072 if(iExist == 0) /* Write a separator */ 00073 fprintf(ath_fp_out, "\n***************************** Appending " 00074 "Output Log *****************************\n\n"); 00075 00076 return 0; 00077 } 00078 00079 /*----------------------------------------------------------------------------*/ 00080 /*! \fn static int ath_log_err_open(void) 00081 * \brief Opens error log file (containing output to stderr). 00082 */ 00083 static int ath_log_err_open(void) 00084 { 00085 int iExist=1; 00086 struct stat statinfo; 00087 00088 open_err_flag = 0; /* zero the flag to open the file, only 1 try if we fail */ 00089 00090 if(log_mode[0] == 'a') 00091 iExist = stat(err_fname, &statinfo); 00092 00093 /* open the ath_fp_err file pointer */ 00094 if((ath_fp_err = fopen(err_fname, log_mode)) == NULL){ 00095 fprintf(stderr,"[ath_log_err_open]: Failed to open ath_fp_err as \"%s\"\n", 00096 err_fname); 00097 return 1; 00098 } 00099 00100 if(iExist == 0) /* Write a separator */ 00101 fprintf(ath_fp_err, "\n***************************** Appending " 00102 "Error Log ******************************\n\n"); 00103 00104 return 0; 00105 } 00106 00107 /*----------------------------------------------------------------------------*/ 00108 /*! \fn void ath_log_set_level(const int out, const int err) 00109 * \brief Sets "output level" and "error level" from input 00110 * arguments, global parameters used by many functions in this file. 00111 * 00112 * Called from main(), where the parameters are parsed from athinput. 00113 */ 00114 void ath_log_set_level(const int out, const int err) 00115 { 00116 out_level = out; 00117 err_level = err; 00118 00119 return; 00120 } 00121 00122 /*----------------------------------------------------------------------------*/ 00123 /*! \fn void ath_log_open(const char *basename, const int lazy, 00124 * const char *mode) 00125 * \brief Opens output and error log files if "lazy" flag is false (0). 00126 * 00127 * If "lazy" is true, then the ath_log_open() call does not actually open the 00128 * files, but rather prepares to open them on the first invocation of either 00129 * ath_pout() ath_perr(), athout_fp() or atherr_fp(). This is useful for 00130 * parallel jobs where the children, if made sufficiently quiet would 00131 * otherwise generate a large number of empty files. -- T. A. Gardiner -- 00132 */ 00133 void ath_log_open(const char *basename, const int lazy, const char *mode) 00134 { 00135 size_t size = strlen(basename) + 5; /* 5 = '.' + 'out' or 'err' + '\0' */ 00136 00137 /* ath_fp_out filename */ 00138 if((out_fname = (char*)malloc(size*sizeof(char))) == NULL){ 00139 fprintf(stderr,"[ath_log_open]: Error constructing filename \"%s.out\"\n", 00140 basename); 00141 exit(EXIT_FAILURE); 00142 } 00143 sprintf(out_fname,"%s.out",basename); 00144 00145 /* ath_fp_err filename */ 00146 if((err_fname = (char*)malloc(size*sizeof(char))) == NULL){ 00147 fprintf(stderr,"[ath_log_open]: Error constructing filename \"%s.err\"\n", 00148 basename); 00149 exit(EXIT_FAILURE); 00150 } 00151 sprintf(err_fname,"%s.err",basename); 00152 00153 /* Copy the mode string - Only "a" and "w" are allowed */ 00154 log_mode[0] = (mode[0] == 'a') ? 'a' : 'w'; 00155 00156 /* Indicate that these files should be opened before any action is done. */ 00157 open_out_flag = open_err_flag = 1; 00158 00159 if(lazy == 0){ 00160 /* open the files now and exit on failure! */ 00161 if(ath_log_out_open() || ath_log_err_open()) 00162 exit(EXIT_FAILURE); 00163 } 00164 00165 return; 00166 } 00167 00168 /*----------------------------------------------------------------------------*/ 00169 /*! \fn void ath_log_close(void) 00170 * \brief Closes output and error log files. 00171 */ 00172 void ath_log_close(void) 00173 { 00174 /* clear the flags to open the log files */ 00175 open_out_flag = open_err_flag = 0; 00176 00177 /* free the log file names */ 00178 if(out_fname != NULL){ free(out_fname); out_fname = NULL; } 00179 if(err_fname != NULL){ free(err_fname); err_fname = NULL; } 00180 00181 /* close the files */ 00182 if(ath_fp_out != NULL){ fclose(ath_fp_out); ath_fp_out = NULL; } 00183 if(ath_fp_err != NULL){ fclose(ath_fp_err); ath_fp_err = NULL; } 00184 00185 return; 00186 } 00187 00188 /*----------------------------------------------------------------------------*/ 00189 /*! \fn FILE *athout_fp(void) 00190 * \brief Open output file if needed and return a pointer to file. 00191 */ 00192 FILE *athout_fp(void) 00193 { 00194 /* Open the output log file if it needs to be opened */ 00195 if(open_out_flag) ath_log_out_open(); 00196 00197 /* Return either the output log file pointer or stdout */ 00198 return (ath_fp_out == NULL ? stdout : ath_fp_out); 00199 } 00200 00201 /*----------------------------------------------------------------------------*/ 00202 /*! \fn FILE *atherr_fp(void) 00203 * \brief Open error file if needed and return a pointer to file. 00204 */ 00205 FILE *atherr_fp(void) 00206 { 00207 /* Open the error log file if it needs to be opened */ 00208 if(open_err_flag) ath_log_err_open(); 00209 00210 /* Return either the error log file pointer or stderr */ 00211 return (ath_fp_err == NULL ? stderr : ath_fp_err); 00212 } 00213 00214 /*----------------------------------------------------------------------------*/ 00215 /*! \fn void ath_flush_out(void) 00216 * \brief Flush output file buffer. 00217 */ 00218 void ath_flush_out(void) 00219 { 00220 FILE *fp; 00221 00222 /* If the output log file needs to be opened then there's no data on 00223 the stream to flush. Return with a successful completion. */ 00224 if(open_out_flag) return; 00225 fp = (ath_fp_out == NULL ? stdout : ath_fp_out); 00226 fflush(fp); 00227 } 00228 00229 /*----------------------------------------------------------------------------*/ 00230 /*! \fn void ath_flush_err(void) 00231 * \brief Flush error file buffer. 00232 */ 00233 void ath_flush_err(void) 00234 { 00235 FILE *fp; 00236 00237 /* If the error log file needs to be opened then there's no data on 00238 the stream to flush. Return with a successful completion. */ 00239 if(open_err_flag) return; 00240 fp = (ath_fp_err == NULL ? stderr : ath_fp_err); 00241 fflush(fp); 00242 } 00243 00244 /*----------------------------------------------------------------------------*/ 00245 /*! \fn int ath_perr(const int level, const char *fmt, ...) 00246 * \brief Foutput variable argument string to "error log file". 00247 * 00248 * Should be used in place of printf(stderr,...) 00249 */ 00250 int ath_perr(const int level, const char *fmt, ...) 00251 { 00252 va_list ap; 00253 int iret = 0; 00254 FILE *fp; 00255 00256 if(level <= err_level){ 00257 /* Open the error log file if it needs to be opened */ 00258 if(open_err_flag) ath_log_err_open(); 00259 00260 /* Use either the error log file pointer or stderr */ 00261 fp = (ath_fp_err == NULL ? stderr : ath_fp_err); 00262 00263 va_start(ap, fmt); /* ap starts after the fmt parameter */ 00264 iret = vfprintf(fp, fmt, ap); /* print the error message to stderr */ 00265 va_end(ap); /* end stdargs (clean up the va_list ap) */ 00266 } 00267 00268 return iret; 00269 } 00270 00271 /*----------------------------------------------------------------------------*/ 00272 /*! \fn int ath_pout(const int level, const char *fmt, ...) 00273 * \brief Output variable argument string to "output log file". 00274 * 00275 * Should be used in place of printf(stdout,...) 00276 */ 00277 int ath_pout(const int level, const char *fmt, ...) 00278 { 00279 va_list ap; 00280 int iret = 0; 00281 FILE *fp; 00282 00283 if(level <= out_level){ 00284 /* Open the output log file if it needs to be opened */ 00285 if(open_out_flag) ath_log_out_open(); 00286 00287 /* Use either the output log file pointer or stdout */ 00288 fp = (ath_fp_out == NULL ? stdout : ath_fp_out); 00289 00290 va_start(ap, fmt); /* ap starts after the fmt parameter */ 00291 iret = vfprintf(fp, fmt, ap); /* print the error message to stderr */ 00292 va_end(ap); /* end stdargs (clean up the va_list ap) */ 00293 } 00294 00295 return iret; 00296 }