diff --git a/src/lam/util/Makefile.am b/src/lam/util/Makefile.am index 4bc48ebc9a..97b5cb77d9 100644 --- a/src/lam/util/Makefile.am +++ b/src/lam/util/Makefile.am @@ -13,8 +13,8 @@ headers = \ argv.h \ cmd_line.h \ few.h \ - lam_log.h \ malloc.h \ + output.h \ path.h \ reactor.h \ strncpy.h @@ -24,7 +24,7 @@ libutil_la_SOURCES = \ argv.c \ cmd_line.c \ few.c \ - lam_log.c \ + output.c \ path.c \ reactor.c \ strncpy.c diff --git a/src/lam/util/lam_log.c b/src/lam/util/lam_log.c deleted file mode 100644 index 38e2f60d12..0000000000 --- a/src/lam/util/lam_log.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $HEADER$ - */ - -#include "lam/util/lam_log.h" -#include -#include - -#define FILE_LINE_MAX 255 -static char file_line[FILE_LINE_MAX + 1] = ""; - -void _lam_log(FILE *fd, const char *fmt, va_list ap) -{ - /* Write to a file descriptor and the log file */ - - if (fd != NULL) { - fprintf(fd, file_line); - vfprintf(fd, fmt, ap); - fflush(fd); - } - - file_line[0] = '\0'; -} - -void _lam_print(FILE * fd, const char *fmt, va_list ap) -{ - /* Write to a file descriptor (usually stdout or stderr) */ - - if (fd != NULL) { - fprintf(fd, file_line); - vfprintf(fd, fmt, ap); - fflush(fd); - } - file_line[0] = '\0'; -} - -void _lam_set_file_line(const char *name, int line) -{ - sprintf(file_line, "LAM/MPI:%s:%d: ", name, line); -} - -void _lam_err(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _lam_log(stderr, fmt, ap); - va_end(ap); -} -void _lam_warn(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _lam_log(stderr, fmt, ap); - va_end(ap); -} - -void _lam_dbg(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _lam_log(stdout, fmt, ap); - va_end(ap); -} - -void _lam_exit(int status, const char* fmt, ...) -{ - va_list ap; - - if (fmt) { - va_start(ap, fmt); - if (status != 0) { - _lam_log(stderr, fmt, ap); - } - else { - _lam_print(stdout, fmt, ap); - } - va_end(ap); - } - - exit(status); -} diff --git a/src/lam/util/lam_log.h b/src/lam/util/lam_log.h deleted file mode 100644 index 9e6ee970b3..0000000000 --- a/src/lam/util/lam_log.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * $HEADER$ - */ - -#ifndef LAM_LOG_H -#define LAM_LOG_H - -#include - - -#define lam_dbg(x) \ -do { \ - if (OPT_DBG) { \ - _lam_set_file_line( __FILE__, __LINE__) ; \ - _lam_dbg x ; \ - } \ -} while (0) - -#define lam_err(x) \ -do { \ - _lam_set_file_line(__FILE__, __LINE__) ; \ - _lam_err x ; \ -} while (0) - -#define lam_warn(x) \ -do { \ - _lam_set_file_line(__FILE__, __LINE__) ; \ - _lam_warn x ; \ -} while (0) - -#define lam_exit(x) \ -do { \ - _lam_set_file_line(__FILE__, __LINE__) ; \ - _lam_exit x ; \ -} while (0) - -/* Error condition */ -void _lam_err(const char* fmt, ...); - -/* Warning condition */ -void _lam_warn(const char* fmt, ...); - -/* Debugging message */ -void _lam_dbg(const char* fmt, ...); - -/* Exit with error message */ -void _lam_exit(int status, const char* fmt, ...); - -/* Set file and line info */ -void _lam_set_file_line(const char *file, int lineno); - - -#endif /* LAM_LOG_H */ - - diff --git a/src/lam/util/output.c b/src/lam/util/output.c new file mode 100644 index 0000000000..4f281d98f3 --- /dev/null +++ b/src/lam/util/output.c @@ -0,0 +1,740 @@ +/* + * $HEADER$ + */ + +#include "lam_config.h" + +#include +#if __STDC__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +#include "lam/constants.h" +#include "lam/util/malloc.h" +#include "lam/util/output.h" +#include "lam/threads/mutex.h" + + +/* + * Private data + */ +int verbose_stream = -1; +int verbose_level = 0; +lam_output_stream_t verbose = { + /* debugging */ + false, + /* verbose level */ + 0, + /* syslog */ + false, 0, NULL, NULL, + /* stdout */ + false, + /* stderr */ + true, + /* file */ + false, false, NULL +}; + + +/* + * Private functions + */ +static void output(int output_id, char *format, va_list arglist); +static char *lam_vsnprintf(char *format, va_list arglist); + + +/* + * Internal data structures and helpers for the generalized output + * stream mechanism. + */ +struct output_desc_t { + bool ldi_used; + bool ldi_enabled; + int ldi_verbose_level; + + bool ldi_syslog; + int ldi_syslog_priority; + char *ldi_syslog_ident; + + char *ldi_prefix; + int ldi_prefix_len; + + bool ldi_stdout; + bool ldi_stderr; + + int ldi_fd; + char *ldi_file_suffix; +}; +typedef struct output_desc_t output_desc_t; + +#define LAM_OUTPUT_MAX_STREAMS 32 + + +/* + * Local state + */ +static bool initialized = false; +static output_desc_t info[LAM_OUTPUT_MAX_STREAMS]; +static char *temp_str = 0; +static int temp_str_len = 0; +static lam_mutex_t mutex; + + +/** + * Initializes the output stream system and opens a default + * "verbose" stream. + * + * @retval true Upon success. + * @retval false Upon failure. + * + * This should be the first function invoked in the output subsystem. + * After this call, the default "verbose" stream is open and can be + * written to via calls to lam_output_verbose() and + * lam_output_error(). + * + * By definition, the default verbose stream has a handle ID of 0, and + * has a verbose level of 0. + */ +bool lam_output_init(void) +{ + int i; + for (i = 0; i < LAM_OUTPUT_MAX_STREAMS; ++i) { + info[i].ldi_used = false; + info[i].ldi_enabled = false; + + info[i].ldi_syslog = false; + info[i].ldi_fd = -1; + } + + /* Initialize the mutex that protects the output */ + + lam_mutex_init(&mutex); + initialized = true; + + /* Open the default verbose stream */ + + verbose_stream = lam_output_open(&verbose); + return true; +} + + +/** + * Opens output streams. + * + * @param lds A pointer to lam_output_stream_t describing what the + * characteristics of the output stream should be. + * + * This function opens an output stream and returns an integer handle. + * The caller is responsible for maintaining the handle and using it + * in successive calls to LAM_OUTPUT(), lam_output(), + * lam_output_switch(), and lam_output_close(). + * + * It is safe to have multiple threads invoke this function + * simultaneously; their execution will be serialized in an + * unspecified manner. + */ +int lam_output_open(lam_output_stream_t *lds) +{ + int i; + int flags; + char *filename; + + /* Setup */ + + if (!initialized) + lam_output_init(); + + /* Find an available stream, or return LAM_ERROR */ + + THREAD_LOCK(&mutex); + for (i = 0; i < LAM_OUTPUT_MAX_STREAMS; ++i) + if (!info[i].ldi_used) + break; + if (i >= LAM_OUTPUT_MAX_STREAMS) { + THREAD_UNLOCK(&mutex); + return LAM_ERR_OUT_OF_RESOURCE; + } + + /* Got a stream -- now initialize it and open relevant outputs */ + + info[i].ldi_used = true; + THREAD_UNLOCK(&mutex); + info[i].ldi_enabled = lds->lds_is_debugging ? (bool) LAM_ENABLE_DEBUG : true; + info[i].ldi_verbose_level = 0; + + info[i].ldi_syslog = lds->lds_want_syslog; + if (lds->lds_want_syslog) { + if (NULL != lds->lds_syslog_ident) { + info[i].ldi_syslog_ident = strdup(lds->lds_syslog_ident); + openlog(lds->lds_syslog_ident, LOG_PID, LOG_USER); + } else { + info[i].ldi_syslog_ident = NULL; + openlog("lam", LOG_PID, LOG_USER); + } + info[i].ldi_syslog_priority = lds->lds_syslog_priority; + } + + if (NULL != lds->lds_prefix) { + info[i].ldi_prefix = strdup(lds->lds_prefix); + info[i].ldi_prefix_len = strlen(lds->lds_prefix); + } else { + info[i].ldi_prefix = NULL; + info[i].ldi_prefix_len = 0; + } + + info[i].ldi_stdout = lds->lds_want_stdout; + info[i].ldi_stderr = lds->lds_want_stderr; + + info[i].ldi_fd = -1; + if (lds->lds_want_file) { + + /* Setup the filename and open flags */ + +#if NEED_TO_IMPLEMENT_SESSION_DIRECTORY + filename = lam_get_tmpdir(); +#else + filename = LAM_MALLOC(256); + strcpy(filename, "/tmp"); +#endif + strcat(filename, "/lam-"); + if (lds->lds_file_suffix != NULL) { + info[i].ldi_file_suffix = strdup(lds->lds_file_suffix); + strcat(filename, lds->lds_file_suffix); + } else { + info[i].ldi_file_suffix = NULL; + strcat(filename, "output.txt"); + } + flags = O_CREAT | O_RDWR; + if (!lds->lds_want_file_append) + flags |= O_TRUNC; + + /* Actually open the file */ + + info[i].ldi_fd = open(filename, flags, 0644); + if (-1 == info[i].ldi_fd) { + info[i].ldi_used = false; + return LAM_ERR_IN_ERRNO; + } + + /* Make the file be close-on-exec to prevent child inheritance + problems */ + + fcntl(info[i].ldi_fd, F_SETFD, 1); + LAM_FREE(filename); + } + + return i; +} + + +/** + * Enables and disables output streams. + * + * @param output_id Stream handle to switch + * @param enable Boolean indicating whether to enable the stream + * output or not. + * + * @returns The previous enable state of the stream (true == enabled, + * false == disabled). + * + * The output of a stream can be temporarily disabled by passing an + * enable value to false, and later resumed by passing an enable value + * of true. This does not close the stream -- it simply tells the + * lam_output subsystem to intercept and discard any output sent to + * the stream via LAM_OUTPUT() or lam_output() until the output is + * re-enabled. + */ +bool lam_output_switch(int output_id, bool enable) +{ + bool ret = false; + + /* Setup */ + + if (!initialized) + lam_output_init(); + + if (output_id >= 0 && output_id < LAM_OUTPUT_MAX_STREAMS) { + ret = info[output_id].ldi_enabled; + info[output_id].ldi_enabled = enable; + } + + return ret; +} + + +/** + * \internal + * + * Reopens all existing output streams. + * + * This function should never be called by user applications; it is + * typically only invoked after a restart (i.e., in a new process) + * where output streams need to be re-initialized. + */ +void lam_output_reopen_all(void) +{ + int i; + lam_output_stream_t lds; + + for (i = 0; i < LAM_OUTPUT_MAX_STREAMS; ++i) { + + /* scan till we find ldi_used == 0, which is the end-marker */ + if (!info[i].ldi_used) + break; + + /* + * set this to zero to ensure that lam_output_open will return this same + * index as the output stream id + */ + info[i].ldi_used = false; + + lds.lds_want_syslog = info[i].ldi_syslog; + lds.lds_syslog_priority = info[i].ldi_syslog_priority; + lds.lds_syslog_ident = info[i].ldi_syslog_ident; + lds.lds_prefix = info[i].ldi_prefix; + lds.lds_want_stdout = info[i].ldi_stdout; + lds.lds_want_stderr = info[i].ldi_stderr; + lds.lds_want_file = (-1 == info[i].ldi_fd) ? false: true; + /* open all streams in append mode */ + lds.lds_want_file_append = true; + lds.lds_file_suffix = info[i].ldi_file_suffix; + + /* + * call lam_output_open to open the stream. The return value is + * guaranteed to be i. So we can ignore it. + */ + lam_output_open(&lds); + } +} + + +/** + * Close an output stream. + * + * @param output_id Handle of the stream to close. + * + * Close an output stream. No output will be sent to the stream after + * it is closed. Be aware that output handles tend to be re-used; it + * is possible that after a stream is closed, if another stream is + * opened, it will get the same handle value. + */ +void lam_output_close(int output_id) +{ + int i; + output_desc_t *ldi; + + /* Setup */ + + if (!initialized) + lam_output_init(); + + /* If it's valid, used, enabled, and has an open file descriptor, + close it */ + + if (output_id >= 0 && output_id < LAM_OUTPUT_MAX_STREAMS && + info[output_id].ldi_used && + info[output_id].ldi_enabled) { + + ldi = &info[output_id]; + + if (-1 != ldi->ldi_fd) + close(ldi->ldi_fd); + ldi->ldi_used = false; + + /* If we strduped a prefix, suffix, or syslog ident, free it */ + + if (NULL != ldi->ldi_prefix) + LAM_FREE(ldi->ldi_prefix); + ldi->ldi_prefix = NULL; + + if (NULL != ldi->ldi_file_suffix) + LAM_FREE(ldi->ldi_file_suffix); + ldi->ldi_file_suffix = NULL; + + if (NULL != ldi->ldi_syslog_ident) + LAM_FREE(ldi->ldi_syslog_ident); + ldi->ldi_syslog_ident = NULL; + } + + /* If no one has the syslog open, we should close it */ + + THREAD_LOCK(&mutex); + for (i = 0; i < LAM_OUTPUT_MAX_STREAMS; ++i) + if (info[i].ldi_used && info[i].ldi_syslog) + break; + if (i >= LAM_OUTPUT_MAX_STREAMS) + closelog(); + + /* Somewhat of a hack to free up the temp_str */ + + if (NULL != temp_str) { + LAM_FREE(temp_str); + temp_str = NULL; + temp_str_len = 0; + } + THREAD_UNLOCK(&mutex); +} + + +/** + * Main function to send output to a stream. + * + * @param output_id Stream id returned from lam_output_open(). + * @param format printf-style format string. + * @param varargs printf-style varargs list to fill the string + * specified by the format parameter. + * + * This is the main function to send output to custom streams (note + * that output to the default "verbose" stream is handled through + * lam_output_verbose() and lam_output_error()). + * + * It is never necessary to send a trailing "\n" in the strings to + * this function; some streams requires newlines, others do not -- + * this function will append newlines as necessary. + * + * Verbosity levels are ignored in this function. + */ +void lam_output(int output_id, char *format, ...) +{ + va_list arglist; +#if __STDC__ + va_start(arglist, format); +#else + va_start(arglist); +#endif + output(output_id, format, arglist); + va_end(arglist); +} + + +/** + * Send output to a stream only if the passed verbosity level is high + * enough. + * + * @param output_id Stream id returned from lam_output_open(). + * @param level Target verbosity level. + * @param format printf-style format string. + * @param varargs printf-style varargs list to fill the string + * specified by the format parameter. + * + * Output is only sent to the stream if the current verbosity level is + * greater than or equal to the level parameter. This mechanism can + * be used to send "information" kinds of output to user applications, + * but only when the user has asked for a high enough verbosity level. + * + * It is never necessary to send a trailing "\n" in the strings to + * this function; some streams requires newlines, others do not -- + * this function will append newlines as necessary. + * + * This function is really a convenience wrapper around checking the + * current verbosity level set on the stream, and if the passed level + * is less than or equal to the stream's verbosity level, this + * function will effectively invoke lam_output to send the output to + * the stream. + * + * @see lam_output_set_verbosity() + */ +void lam_output_verbose(int output_id, int level, char *format, ...) +{ + if (info[output_id].ldi_verbose_level >= level) { + va_list arglist; +#if __STDC__ + va_start(arglist, format); +#else + va_start(arglist); +#endif + output(output_id, format, arglist); + va_end(arglist); + } +} + + +/** + * Set the verbosity level for a stream. + * + * @param output_id Stream id returned from lam_output_open(). + * @param level New verbosity level + * + * This function sets the verbosity level on a given stream. It will + * be used for all future invocations of lam_output_verbose(). + */ +void lam_output_set_verbosity(int output_id, int level) +{ + info[output_id].ldi_verbose_level = level; +} + + +/** + * Shut down the output stream system. + * + * Shut down the output stream system, including the default verbose + * stream. + */ +void lam_output_finalize(void) +{ + if (initialized) { + if (verbose_stream != -1) + lam_output_close(verbose_stream); + verbose_stream = -1; + } +} + +/* + * Do the actual output. Take a va_list so that we can be called from + * multiple different places, even functions that took "..." as input + * arguments. + */ +static void output(int output_id, char *format, va_list arglist) +{ + int len, total_len; + bool want_newline = false; + char *str; + output_desc_t *ldi; + + /* Setup */ + + if (!initialized) + lam_output_init(); + + /* If it's valid, used, and enabled, output */ + + if (output_id >= 0 && output_id < LAM_OUTPUT_MAX_STREAMS && + info[output_id].ldi_used && + info[output_id].ldi_enabled) { + ldi = &info[output_id]; + + /* Make the formatted string */ + + THREAD_LOCK(&mutex); + str = lam_vsnprintf(format, arglist); + total_len = len = strlen(str); + if ('\n' != str[len - 1]) { + want_newline = true; + ++total_len; + } + if (NULL != ldi->ldi_prefix) + total_len += strlen(ldi->ldi_prefix); + if (temp_str_len < total_len + want_newline) { + if (NULL != temp_str) + LAM_FREE(temp_str); + temp_str = malloc(total_len * 2); + temp_str_len = total_len * 2; + } + if (NULL != ldi->ldi_prefix) { + if (want_newline) + snprintf(temp_str, temp_str_len, "%s%s\n", ldi->ldi_prefix, str); + else + snprintf(temp_str, temp_str_len, "%s%s", ldi->ldi_prefix, str); + } else { + if (want_newline) + snprintf(temp_str, temp_str_len, "%s\n", str); + else + snprintf(temp_str, temp_str_len, "%s", str); + } + + /* Syslog output */ + + if (ldi->ldi_syslog) + syslog(ldi->ldi_syslog_priority, str); + + /* stdout output */ + + if (ldi->ldi_stdout) { + printf(temp_str); + fflush(stdout); + } + + /* stderr output */ + + if (ldi->ldi_stderr) { + fprintf(stderr, temp_str); + fflush(stderr); + } + + /* File output */ + + if (ldi->ldi_fd != -1) + write(ldi->ldi_fd, temp_str, total_len); + THREAD_UNLOCK(&mutex); + + LAM_FREE(str); + } +} + + +/* + * lam_vsnprintf + * + * Make a good guess about how long a printf-style varags formatted + * string will be once all the % escapes are filled in. We don't + * handle every % escape here, but we handle enough, and then add a + * fudge factor in at the end. When we have that, alloc out a buffer + * and snprintf into it. The whole reason for this routine is because + * we can't count on vsnprintf to be on every system. :-( Ok, it's + * not exactly the same as vsnprintf, but it's in the same spirit, so + * it's ok to use a derrivative of the name... + */ +static char *lam_vsnprintf(char *format, va_list arglist) +{ + int i, len; + char *sarg; + int iarg; + long larg; + double darg; + float farg; + + /* Important: keep a copy of the original arglist because when we + traverse through the original arglist, it has internal state that + knows where it is in the list of args. At the end of this + routine, we'll need the whole list in order to call vsprintf(), + and there doesn't appear to be a way to "rewind" a va_alist. + + Copy order taken from Autoconf docs + */ + va_list arglist2; +#if LAM_HAVE_VA_COPY + va_copy(arglist2, arglist); +#elif LAM_HAVE_UNDERSCORE_VA_COPY + __va_copy(arglist2, arglist); +#else + memcpy (&arglist2, &arglist, sizeof(va_list)); +#endif + + /* Start off with a fudge factor of 128 to handle the % escapes that + we aren't calculating here */ + + len = strlen(format) + 128; + for (i = 0; i < strlen(format); ++i) { + if ('%' == format[i] && i + 1 < strlen(format) && '%' != format[i + 1]) { + ++i; + switch(format[i]) { + case 's': + sarg = va_arg(arglist, char*); + /* If there's an arg, get the strlen, otherwise we'll use (null) */ + if (NULL != sarg) + len += strlen(sarg); + else + len += 5; + break; + + case 'd': + case 'i': + iarg = va_arg(arglist, int); + /* Alloc for minus sign */ + if (iarg < 0) + ++len; + /* Now get the log10 */ + do { + ++len; + iarg /= 10; + } while (0 != iarg); + break; + + case 'x': + case 'X': + iarg = va_arg(arglist, int); + /* Now get the log16 */ + do { + ++len; + iarg /= 16; + } while (0 != iarg); + break; + + case 'f': + farg = va_arg(arglist, int); + /* Alloc for minus sign */ + if (farg < 0) { + ++len; + farg = -farg; + } + /* Alloc for 3 decimal places + '.' */ + len += 4; + /* Now get the log10 */ + do { + ++len; + farg /= 10.0; + } while (0 != farg); + break; + + case 'g': + darg = va_arg(arglist, int); + /* Alloc for minus sign */ + if (darg < 0) { + ++len; + darg = -darg; + } + /* Alloc for 3 decimal places + '.' */ + len += 4; + /* Now get the log10 */ + do { + ++len; + darg /= 10.0; + } while (0 != darg); + break; + + case 'l': + /* Get %ld %lx %lX %lf */ + if (i + 1 < strlen(format)) { + ++i; + switch(format[i]) { + case 'x': + case 'X': + larg = va_arg(arglist, int); + /* Now get the log16 */ + do { + ++len; + larg /= 16; + } while (0 != larg); + break; + + case 'f': + darg = va_arg(arglist, int); + /* Alloc for minus sign */ + if (darg < 0) { + ++len; + darg = -darg; + } + /* Alloc for 3 decimal places + '.' */ + len += 4; + /* Now get the log10 */ + do { + ++len; + darg /= 10.0; + } while (0 != darg); + break; + + case 'd': + default: + larg = va_arg(arglist, int); + /* Now get the log10 */ + do { + ++len; + larg /= 10; + } while (0 != larg); + break; + } + } + + default: + break; + } + } + } + + /* Wasn't that simple? Now malloc out a string and do the final + formatting into that string. */ + + sarg = LAM_MALLOC(len); + vsprintf(sarg, format, arglist2); + + /* Return the new string */ + + return sarg; +} diff --git a/src/lam/util/output.h b/src/lam/util/output.h new file mode 100644 index 0000000000..36ec03e97b --- /dev/null +++ b/src/lam/util/output.h @@ -0,0 +1,223 @@ +/* + * $HEADER$ + */ + +/** @file + * LAM output stream facility. + * + * The LAM output stream facility is used to send output from the LAM + * libraries to output devices. It is meant to fully replace all + * forms of printf() (and friends). Output streams are opened via the + * lam_output_open() function call, and then sent output via + * lam_output_verbose(), LAM_OUTPUT(), and lam_output(). Streams are + * closed with lam_output_close(). + * + * Streams can multiplex output to several kinds of outputs (one of + * each): + * + * - the syslog + * - standard output + * - standard error + * - file + * + * Which outputs to use are specified during lam_output_open(). + * + * lam_output_open() returns an integer handle that is used in + * successive calls to LAM_OUTPUT() and lam_output() to send output to + * the stream. + * + * The default "verbose" stream is opened after invoking + * lam_output_init() (and closed after invoking + * lam_output_finalize()). This stream outputs to stderr only, and + * has a stream handle ID of 0. + * + * It is erroneous to have one thread close a stream and have another + * try to write to it. Multiple threads writing to a single stream + * will be serialized in an unspecified order. + */ + +#ifndef LAM_OUTPUT_H_ +#define LAM_OUTPUT_H_ + +#include "lam_config.h" + +#if __STDC__ +#include +#else +#ifdef __cplusplus +#include +#else +#include +#endif +#endif /* __STDC__ */ + + +/** + * \class lam_output_stream_t + * + * Structure used to request the opening of a LAM output stream. A + * pointer to this structure is passed to lam_output_open() to tell + * the lam_output subsystem where to send output for a given stream. + * It is valid to specify multiple destinations of output for a stream + * -- output streams can be multiplexed to multiple different + * destinations through the lam_output facility. + * + * Note that all strings in this struct are cached on the stream by + * value; there is no need to keep them allocated after the return + * from lam_output_open(). + * + * @see output.h + */ +struct lam_output_stream_t { + /** + * Indicates whether the output of the stream is + * debugging/developer-only output or not. + * + * This field should be "true" if the output is for debugging + * purposes only. In that case, the output will never be sent to + * the stream unless LAM was configured with --enable-debug. + */ + bool lds_is_debugging; + + /** + * Indicate the starting verbosity level of the stream. + * + * Verbose levels are a convenience mechanisms, and are only + * consulted when output is sent to a stream through the + * lam_output_verbose() function. Verbose levels are ignored in + * LAM_OUTPUT() and lam_output(). + * + * Valid verbose levels typically start at 0 (meaning "minimal + * information"). Higher verbosity levels generally indicate that + * more output and diagnostics should be displayed. + */ + int lda_verbose_level; + + /** + * Indicates whether output of the stream should be sent to the + * syslog or not. + * + * If this field is true, output from this stream is sent to the + * syslog, and the following fields are also examined: + * + * - lds_syslog_priority + * - lds_syslog_ident + * - lds_prefix + * + * If this field is false, the above three fields are ignored. + */ + bool lds_want_syslog; + /** + * When lam_output_stream_t::lds_want_syslog is true, this field is + * examined to see what priority output from the stream should be + * sent to the syslog. + * + * This value should be set as per the syslog(3) man page. It is + * typically the OR value of "facilty" and "level" values described + * in the man page. + */ + int lds_syslog_priority; + /** + * When lam_output_stream_t::lds_want_syslog is true, this field is + * examined to see what ident value should be passed to openlog(3). + * + * If a NULL value is given, the string "lam" is used. + */ + char *lds_syslog_ident; + + /** + * String prefix added to all output on the stream. + * + * When this field is non-NULL, it is prefixed to all lines of + * output on the stream. When this field is NULL, no prefix is + * added to each line of output in the stream. + */ + char *lds_prefix; + + /** + * Whether to send stream output to stdout or not. + * + * If this field is true, stream output is sent to stdout. + */ + bool lds_want_stdout; + /** + * Whether to send stream output to stderr or not. + * + * If this field is true, stream output is sent to stderr. + */ + bool lds_want_stderr; + + /** + * Whether to send stream output to a file or not. + * + * When this field is true, stream output is sent to a file, and the + * following fields are also examined: + * + * - lds_want_file_append + * - lda_file_suffix + */ + bool lds_want_file; + /** + * When lam_output_stream_t::lds_want_file is true, this field + * indicates whether to append the file (if it exists) or overwrite + * it. + * + * If false, the file is opened with the O_TRUNC flag. + */ + bool lds_want_file_append; + /** + * When lam_output_stream_t::lds_want_file is true, this field + * indicates the string suffix to add to the filename. + * + * The output file will be in the LAM session directory and have a + * LAM-generated prefix (generally "$sessiondir/lam-"). The suffix + * is intended to give stream users a chance to write their output + * into unique files. If this field is NULL, the suffix + * "output.txt" is used. + */ + char *lds_file_suffix; +}; + +typedef struct lam_output_stream_t lam_output_stream_t; + + +#ifdef __cplusplus +extern "C" { +#endif + bool lam_output_init(void); + void lam_output_finalize(void); + + int lam_output_open(lam_output_stream_t *lds); + bool lam_output_switch(int output_id, bool enable); + void lam_output_reopen_all(void); + void lam_output_close(int output_id); + + void lam_output(int output_id, char *format, ...); + void lam_output_verbose(int output_id, int verbose_level, char *format, ...); + void lam_output_set_verbosity(int output_id, int level); + +#if LAM_ENABLE_DEBUG + /** + * Main macro for use in sending debugging output to output streams; + * will be "compiled out" when LAM is configured without + * --enable-debug. + * + * @see lam_output() + */ +#define LAM_OUTPUT(a) lam_output a +#else + /** + * Main macro for use in sending debugging output to output streams; + * will be "compiled out" when LAM is configured without + * --enable-debug. + * + * @see lam_output() + */ +#define LAM_OUTPUT(a) +#endif +#ifdef __cplusplus +} +#endif + +#endif /* LAM_OUTPUT_H_ */ +