MACSio  0.9
Multi-purpose, Application-Centric, Scalable I/O Proxy App
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
macsio_log.c
Go to the documentation of this file.
1 /*
2 Copyright (c) 2015, Lawrence Livermore National Security, LLC.
3 Produced at the Lawrence Livermore National Laboratory.
4 Written by Mark C. Miller
5 
6 LLNL-CODE-676051. All rights reserved.
7 
8 This file is part of MACSio
9 
10 Please also read the LICENSE file at the top of the source code directory or
11 folder hierarchy.
12 
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License (as published by the Free Software
15 Foundation) version 2, dated June 1991.
16 
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the terms and conditions of the GNU General
20 Public License for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24 Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26 
27 #include <fcntl.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 
36 #include <macsio_log.h>
37 
43 int mpi_errno = MPI_SUCCESS;
47 
48 typedef struct _log_flags_t
49 {
50  unsigned int was_logged : 1;
51 } log_flags_t;
52 
54 {
55 #ifdef HAVE_MPI
56  MPI_Comm comm;
57 #else
58  int comm;
59 #endif
60  char *pathname;
61  int logfile;
62  int rank;
63  int size;
67 #warning FIX USE OF MUTABLE HERE
68  mutable int current_line;
70  mutable log_flags_t flags;
72 
78 char const *
80  char const *format,
81  ...
82 )
83 {
84 #warning MAKE THIS THREAD SAFE BY ALLOCATING THE RETURNED STRING OR USE A LARGE CIRCULAR BUFFER
85  static char error_buffer[1024];
86  static int error_buffer_ptr = 0;
87  size_t L,Lmax;
88  char tmp[sizeof(error_buffer)];
89  va_list ptr;
90 
91  va_start(ptr, format);
92 
93  vsprintf(tmp, format, ptr);
94  L = strlen(tmp);
95  Lmax = sizeof(error_buffer) - error_buffer_ptr - 1;
96  if (Lmax < L)
97  tmp[Lmax-1] = '\0';
98  strcpy(error_buffer + error_buffer_ptr,tmp);
99 
100  va_end(ptr);
101 
102  return error_buffer;
103 }
104 
114 #ifdef HAVE_MPI
115  MPI_Comm comm,
116 #else
117  int comm,
118 #endif
119  char const *path,
120  int line_len,
121  int lines_per_proc,
122  int extra_lines_proc0
123 )
124 {
125  int rank=0, size=1;
126  MACSIO_LOG_LogHandle_t *retval;
127 
128  if (line_len <= 0) line_len = MACSIO_LOG_DEFAULT_LINE_LENGTH;
129  if (lines_per_proc <= 0) lines_per_proc = MACSIO_LOG_DEFAULT_LINE_COUNT;
130  if (extra_lines_proc0 <= 0) extra_lines_proc0 = MACSIO_LOG_DEFAULT_EXTRA_LINES;
131 
132 #ifdef HAVE_MPI
133  MPI_Comm_size(comm, &size);
134  MPI_Comm_rank(comm, &rank);
135 #endif
136 
137  /* Rank 0 "primes" the log file; creates it, populates it
138  with processor header lines and spaces and closes it */
139  if (path && rank == 0)
140  {
141  int i, filefd;
142  char *linbuf = (char*) malloc(line_len * (lines_per_proc + extra_lines_proc0) * sizeof(char));
143  memset(linbuf, '-', line_len * sizeof(char));
144  memset(linbuf+line_len, ' ', line_len * (lines_per_proc + extra_lines_proc0 - 1) * sizeof(char));
145  for (i = 0; i < lines_per_proc+extra_lines_proc0; i++)
146  linbuf[(i+1)*line_len-1] = '\n';
147  filefd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP);
148  for (i = 0; i < size; i++)
149  {
150  char tmp[32];
151  sprintf(tmp, "Processor %06d", i);
152  memcpy(linbuf+line_len/2-strlen(tmp)/2, tmp, strlen(tmp));
153  if (i == 0)
154  write(filefd, linbuf, sizeof(char) * line_len * (lines_per_proc+extra_lines_proc0));
155  else
156  write(filefd, linbuf, sizeof(char) * line_len * lines_per_proc);
157  }
158  close(filefd);
159  }
160 
161 #ifdef HAVE_MPI
162  mpi_errno = MPI_Barrier(comm);
163 #endif
164 
165  retval = (MACSIO_LOG_LogHandle_t *) malloc(sizeof(MACSIO_LOG_LogHandle_t));
166  retval->pathname = path?strdup(path):0;
167  retval->comm = comm;
168  retval->logfile = path?open(path, O_WRONLY):fileno(stderr);
169  retval->size = size;
170  retval->rank = rank;
171  retval->log_line_length = path?line_len:1024;
172  retval->lines_per_proc = path?lines_per_proc:1000000;
173  retval->extra_lines_proc0 = path?extra_lines_proc0:0;
174  retval->current_line = 1; /* never write to line '0' to preserve "Processor XXXX" headings */
175  retval->flags.was_logged = 0;
176  errno = 0;
177  return retval;
178 }
179 
185 void
187  MACSIO_LOG_LogHandle_t const *log,
188  char const *fmt,
189  ...
190 )
191 {
192  int i = 0;
193  int is_stderr = log->logfile == fileno(stderr);
194  char *msg, *buf;
195  va_list ptr;
196 
197  msg = (char *) malloc(log->log_line_length+10);
198  buf = (char *) malloc(log->log_line_length+10);
199 
200  if (is_stderr) sprintf(msg, "%06d: ", log->rank);
201  va_start(ptr, fmt);
202  vsnprintf(is_stderr?&msg[8]:msg, log->log_line_length-1, fmt, ptr);
203  va_end(ptr);
204  msg[log->log_line_length-1] = '\0';
205 
206  while (i < strlen(msg) && i < log->log_line_length)
207  {
208  if (msg[i] == '\n')
209  buf[i] = '!';
210  else
211  buf[i] = msg[i];
212  i++;
213  }
214  free(msg);
215  if (is_stderr)
216  {
217  buf[i++] = '\n';
218  buf[i++] = '\0';
219  }
220  else
221  {
222  while (i < log->log_line_length)
223  buf[i++] = ' ';
224  buf[log->log_line_length-1] = '\n';
225  }
226 
227  if (is_stderr)
228  {
229  write(log->logfile, buf, sizeof(char) * strlen(buf));
230  }
231  else
232  {
233  int extra_lines = log->rank?log->extra_lines_proc0:0;
234  off_t seek_offset = (log->rank * log->lines_per_proc + log->current_line + extra_lines) * log->log_line_length;
235  pwrite(log->logfile, buf, sizeof(char) * log->log_line_length, seek_offset);
236  }
237  free(buf);
238 
239  log->current_line++;
240  if (log->current_line == log->lines_per_proc + (log->rank==0?log->extra_lines_proc0:0))
241  log->current_line = 1;
242  log->flags.was_logged = 1;
243 }
244 
248 void
250  MACSIO_LOG_LogHandle_t const *log,
251  char const *linemsg,
252  MACSIO_LOG_MsgSeverity_t sevVal,
253  char const *sevStr,
254  int sysErrno,
255  int mpiErrno,
256  char const *theFile,
257  int theLine
258 )
259 {
260  char _sig[512], _msg[512], _err[512];
261  char _mpistr[MPI_MAX_ERROR_STRING+1], _mpicls[MPI_MAX_ERROR_STRING+1];
262  _sig[0] = _msg[0] = _err[0] = _mpistr[0] = _mpicls[0] = '\0';
263  if (sevVal <= MACSIO_LOG_MsgDbg3 && sevVal >= MACSIO_LOG_DebugLevel)
264  return;
265  snprintf(_sig, sizeof(_sig), "%.4s:\"%s\":%d", sevStr, theFile, theLine);
266  snprintf(_msg, sizeof(_msg), "%s", linemsg);
267  if (sysErrno)
268  snprintf(_err, sizeof(_err), "%d:\"%s\"", sysErrno, strerror(sysErrno));
269 #ifdef HAVE_MPI
270  if (mpiErrno != MPI_SUCCESS)
271  {
272  int mpi_errcls, len;
273  MPI_Error_class(mpiErrno, &mpi_errcls);
274  MPI_Error_string(mpi_errcls, _mpicls, &len);
275  _mpicls[len] = '\0';
276  MPI_Error_string(mpiErrno, _mpistr, &len);
277  _mpistr[len] = '\0';
278  }
279 #endif
280 #warning CLEAN UP SO ONLY PRINT NON-EMPTY STRINGS
281  MACSIO_LOG_LogMsg(log, "%s:%s:%s:%s:%s", _sig, _msg, _err, _mpistr, _mpicls);
282  if (sevVal == MACSIO_LOG_MsgDie)
283 #ifdef HAVE_MPI
284  MPI_Abort(MPI_COMM_WORLD, 0);
285 #else
286  abort(sysErrno);
287 #endif
288 }
289 
294 void
297 )
298 {
299  int was_logged = log->flags.was_logged;
300  int reduced_was_logged = was_logged;
301 
302 #warning ADD ATEXIT FUNCTIONALITY TO CLOSE LOGS
303  if (log->logfile != fileno(stderr))
304  close(log->logfile);
305 
306 #ifdef HAVE_MPI
307  MPI_Reduce(&was_logged, &reduced_was_logged, 1, MPI_INT, MPI_MAX, 0, log->comm);
308 #endif
309 
310  /* If there was no message logged, we remove the log */
311  if (log->rank == 0 && !reduced_was_logged && log->pathname)
312  unlink(log->pathname);
313 
314  if (log->pathname) free(log->pathname);
315  free(log);
316 }
317 
MACSIO_LOG_LogHandle_t * MACSIO_LOG_StdErr
Log handle for MACSIO's stderr output.
Definition: macsio_log.c:46
char const * MACSIO_LOG_MakeMsg(char const *format,...)
Internal convenience method to build a message from a printf-style format string and args...
Definition: macsio_log.c:79
int mpi_errno
Error code returned by most recent MPI call.
Definition: macsio_log.c:43
MACSIO_LOG_LogHandle_t * MACSIO_LOG_LogInit(MPI_Comm comm, char const *path, int line_len, int lines_per_proc, int extra_lines_proc0)
Initialize a log.
Definition: macsio_log.c:113
struct _MACSIO_LOG_LogHandle_t MACSIO_LOG_LogHandle_t
#define MACSIO_LOG_DEFAULT_LINE_COUNT
Definition: macsio_log.h:115
enum _MACSIO_LOG_MsgSeverity_t MACSIO_LOG_MsgSeverity_t
void MACSIO_LOG_LogFinalize(MACSIO_LOG_LogHandle_t *log)
Finalize and close an open log Should be called collectively by all processors that created the log...
Definition: macsio_log.c:295
int MACSIO_LOG_DebugLevel
Definition: macsio_log.c:44
#define MACSIO_LOG_DEFAULT_EXTRA_LINES
Definition: macsio_log.h:120
MACSIO_LOG_LogHandle_t * MACSIO_LOG_MainLog
Log handle for MACSIO's main log.
Definition: macsio_log.c:45
void MACSIO_LOG_LogMsg(MACSIO_LOG_LogHandle_t const *log, char const *fmt,...)
Issue a printf-style message to a log.
Definition: macsio_log.c:186
void MACSIO_LOG_LogMsgWithDetails(MACSIO_LOG_LogHandle_t const *log, char const *linemsg, MACSIO_LOG_MsgSeverity_t sevVal, char const *sevStr, int sysErrno, int mpiErrno, char const *theFile, int theLine)
Convenience method for building a detailed message for a log.
Definition: macsio_log.c:249
unsigned int was_logged
Definition: macsio_log.c:50
#define MACSIO_LOG_DEFAULT_LINE_LENGTH
Definition: macsio_log.h:125
struct _log_flags_t log_flags_t