| /*****************************************************************************\ |
| * log.h - configurable logging for slurm: log to file, stderr and/or syslog. |
| ***************************************************************************** |
| * Copyright (C) 2002-2007 The Regents of the University of California. |
| * Copyright (C) 2008-2010 Lawrence Livermore National Security. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Mark Grondona <mgrondona@llnl.gov> |
| * CODE-OCEC-09-009. All rights reserved. |
| * |
| * Much of this code was derived or adapted from the log.c component of |
| * openssh which contains the following notices: |
| ***************************************************************************** |
| * Author: Tatu Ylonen <ylo@cs.hut.fi> |
| * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
| * All rights reserved |
| * |
| * As far as I am concerned, the code I have written for this software |
| * can be used freely for any purpose. Any derived versions of this |
| * software must be clearly marked as such, and if the derived work is |
| * incompatible with the protocol description in the RFC file, it must be |
| * called by a name other than "ssh" or "Secure Shell". |
| ***************************************************************************** |
| * Copyright (c) 2000 Markus Friedl. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| \*****************************************************************************/ |
| |
| #ifndef _LOG_H |
| #define _LOG_H |
| |
| #include <syslog.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| #include "slurm/slurm.h" |
| #include "src/common/macros.h" |
| #include "src/common/cbuf.h" |
| |
| /* supported syslog facilities and levels */ |
| typedef enum { |
| SYSLOG_FACILITY_DAEMON = LOG_DAEMON, |
| SYSLOG_FACILITY_USER = LOG_USER, |
| SYSLOG_FACILITY_AUTH = LOG_AUTH, |
| #ifdef LOG_AUTHPRIV |
| SYSLOG_FACILITY_AUTHPRIV = LOG_AUTHPRIV, |
| #endif |
| SYSLOG_FACILITY_LOCAL0 = LOG_LOCAL0, |
| SYSLOG_FACILITY_LOCAL1 = LOG_LOCAL1, |
| SYSLOG_FACILITY_LOCAL2 = LOG_LOCAL2, |
| SYSLOG_FACILITY_LOCAL3 = LOG_LOCAL3, |
| SYSLOG_FACILITY_LOCAL4 = LOG_LOCAL4, |
| SYSLOG_FACILITY_LOCAL5 = LOG_LOCAL5, |
| SYSLOG_FACILITY_LOCAL6 = LOG_LOCAL6, |
| SYSLOG_FACILITY_LOCAL7 = LOG_LOCAL7 |
| } log_facility_t; |
| |
| /* |
| * log levels, logging will occur at or below the selected level |
| * QUIET disable logging completely. |
| */ |
| typedef enum { |
| LOG_LEVEL_QUIET = 0, |
| LOG_LEVEL_FATAL, |
| LOG_LEVEL_ERROR, |
| LOG_LEVEL_INFO, |
| LOG_LEVEL_VERBOSE, |
| LOG_LEVEL_DEBUG, |
| LOG_LEVEL_DEBUG2, |
| LOG_LEVEL_DEBUG3, |
| LOG_LEVEL_DEBUG4, |
| LOG_LEVEL_DEBUG5, |
| LOG_LEVEL_END |
| } log_level_t; |
| |
| typedef enum { |
| LOG_FILE_FMT_TIMESTAMP = 0, |
| LOG_FILE_FMT_JSON, |
| } log_file_fmt_t; |
| |
| /* |
| * log options: Each of stderr, syslog, and logfile can have a different level |
| */ |
| typedef struct { |
| log_level_t stderr_level; /* max level to log to stderr */ |
| log_level_t syslog_level; /* max level to log to syslog */ |
| log_level_t logfile_level; /* max level to log to logfile */ |
| bool prefix_level; /* prefix level (e.g. "debug: ") if true */ |
| bool buffered; /* use internal buffer to never block */ |
| bool raw; /* output is to a raw terminal */ |
| log_file_fmt_t logfile_fmt; /* format of logfile output */ |
| } log_options_t; |
| |
| /* some useful initializers for log_options_t |
| */ |
| #define LOG_OPTS_INITIALIZER \ |
| { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_INFO, \ |
| 1, 0, 0, LOG_FILE_FMT_TIMESTAMP } |
| |
| #define LOG_OPTS_SYSLOG_DEFAULT \ |
| { LOG_LEVEL_QUIET, LOG_LEVEL_INFO, LOG_LEVEL_QUIET, \ |
| 1, 0, 0, LOG_FILE_FMT_TIMESTAMP } |
| |
| #define LOG_OPTS_STDERR_ONLY \ |
| { LOG_LEVEL_INFO, LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, \ |
| 1, 0, 0, LOG_FILE_FMT_TIMESTAMP } |
| |
| #define SCHEDLOG_OPTS_INITIALIZER \ |
| { LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, \ |
| 0, 1, 0, LOG_FILE_FMT_TIMESTAMP } |
| |
| |
| /* Functions for filling in a char buffer with a timestamp. */ |
| size_t rfc2822_timestamp(char *, size_t); |
| size_t log_timestamp(char *, size_t); |
| |
| |
| /* |
| * initialize log module (called only once) |
| * |
| * example: |
| * |
| * To initialize log module to print fatal messages to stderr, and |
| * all messages up to and including info() to syslog: |
| * |
| * log_options_t logopts = LOG_OPTS_INITIALIZER; |
| * logopts.stderr_level = LOG_LEVEL_FATAL; |
| * logopts.syslog_level = LOG_LEVEL_INFO; |
| * |
| * rc = log_init(argv[0], logopts, SYSLOG_FACILITY_DAEMON, NULL); |
| * |
| * log function automatically takes the basename() of argv0. |
| */ |
| int log_init(char *argv0, log_options_t opts, |
| log_facility_t fac, char *logfile); |
| |
| /* |
| * initialize scheduler log module (called only once) |
| */ |
| int sched_log_init(char *argv0, log_options_t opts, log_facility_t fac, |
| char *logfile); |
| |
| /* reinitialize log module. |
| * Keep same log options as previously initialized log, but reinit mutex |
| * that protects the log. This call is needed after a fork() in a threaded |
| * program |
| */ |
| void log_reinit(void); |
| |
| /* |
| * Close log and free associated memory |
| */ |
| void log_fini(void); |
| |
| /* |
| * Close scheduler log and free associated memory |
| */ |
| void sched_log_fini(void); |
| |
| /* Alter log facility, options are like log_init() above, except that |
| * an argv0 argument is not passed. |
| * |
| * This function may be called multiple times. |
| */ |
| int log_alter(log_options_t opts, log_facility_t fac, char *logfile); |
| |
| /* Alter log facility, options are like log_alter() above, except that |
| * an the file pointer is sent in instead of a filename. |
| * |
| * This function may only be called once. |
| */ |
| int log_alter_with_fp(log_options_t opt, log_facility_t fac, FILE *fp_in); |
| |
| /* Sched alter log facility, options are like sched_log_init() above, |
| * except that an argv0 argument is not passed. |
| * |
| * This function may be called multiple times. |
| */ |
| int sched_log_alter(log_options_t opts, log_facility_t fac, char *logfile); |
| |
| /* Set prefix for log file entries |
| * Note: will store pfx internally, do not use after this call. |
| */ |
| void log_set_prefix(char **pfx); |
| |
| /* |
| * (re)set argv0 string prepended to all log messages |
| */ |
| void log_set_argv0(char *pfx); |
| |
| /* Return the FILE * of the current logfile (or stderr if not logging to |
| * a file, but NOT both). Also see log_oom() below. */ |
| FILE *log_fp(void); |
| |
| /* Log out of memory without message buffering */ |
| void log_oom(const char *file, int line, const char *func); |
| |
| /* Set the log timestamp format */ |
| void log_set_timefmt(unsigned); |
| |
| /* |
| * Buffered log functions: |
| * |
| * log_has_data() returns true if there is data in the |
| * internal log buffer |
| */ |
| bool log_has_data(void); |
| |
| /* |
| * log_flush() attempts to flush all data in the internal |
| * log buffer to the appropriate output stream. |
| */ |
| void log_flush(void); |
| |
| /* log_set_debug_flags() |
| * Set or reset the debug flags based on the configuration |
| * file or the scontrol command. |
| */ |
| extern void log_set_debug_flags(void); |
| |
| /* Return the highest LOG_LEVEL_* used for any logging mechanism. |
| * For example, if LOG_LEVEL_INFO is returned, we know that all verbose and |
| * debug type messages will be ignored. */ |
| extern int get_log_level(void); |
| |
| /* |
| * Returns the greater of the sched_log_level or the log_level. |
| */ |
| extern int get_sched_log_level(void); |
| |
| |
| #define STEP_ID_FLAG_NONE 0x0000 |
| #define STEP_ID_FLAG_PS 0x0001 |
| #define STEP_ID_FLAG_NO_JOB 0x0002 |
| #define STEP_ID_FLAG_NO_PREFIX 0x0004 |
| #define STEP_ID_FLAG_SPACE 0x0008 |
| |
| /* |
| * log_build_step_id_str() - print a slurm_step_id_t as " StepId=...", with |
| * Batch and Extern used as appropriate. |
| */ |
| extern char *log_build_step_id_str( |
| slurm_step_id_t *step_id, char *buf, int buf_size, uint16_t flags); |
| |
| /* |
| * the following log a message to the log facility at the appropriate level: |
| * |
| * Messages do not need a newline! |
| * |
| * args are printf style with the following exceptions: |
| * %m expands to strerror(errno) |
| * %M expand to time stamp, format is configuration dependent |
| * %pJ expands to "JobId=XXXX" for the given job_ptr, with the appropriate |
| * format for job arrays and hetjob components. |
| * %pS expands to "JobId=XXXX StepId=YYYY" for a given step_ptr. |
| * %t expands to strftime("%x %X") [ locally preferred short date/time ] |
| * %T expands to rfc2822 date time [ "dd, Mon yyyy hh:mm:ss GMT offset" ] |
| */ |
| |
| /* |
| * return a heap allocated string formed from fmt and ap arglist |
| * returned string is allocated with xmalloc, so must free with xfree. |
| * |
| * args are like printf, with the addition of the following format chars: |
| * - %m expands to strerror(errno) |
| * - %M expand to time stamp, format is configuration dependent |
| * - %pA expands to "AAA.BBB.CCC.DDD:XXXX" for the given slurm_addr_t. |
| * - %pd expands to compact JSON serialization for the given data_t*. |
| * - %pD expands to "type(0xDEADBEEF)" for the given data_t*. |
| * - %pJ expands to "JobId=XXXX" for the given job_ptr, with the appropriate |
| * format for job arrays and hetjob components. |
| * - %pS expands to "JobId=XXXX StepId=YYYY" for a given step_ptr. |
| * - %t expands to strftime("%x %X") [ locally preferred short date/time ] |
| * - %T expands to rfc2822 date time [ "dd, Mon yyyy hh:mm:ss GMT offset" ] |
| * |
| * these formats are expanded first, leaving all others to be passed to |
| * vsnprintf() to complete the expansion using the ap arglist. |
| */ |
| extern char *vxstrfmt(const char *fmt, va_list ap); |
| |
| /* |
| * fatal() exits program |
| * error() returns SLURM_ERROR |
| */ |
| void log_var(const log_level_t, const char *, ...) |
| __attribute__ ((format (printf, 2, 3))); |
| void sched_log_var(const log_level_t, const char *, ...) |
| __attribute__ ((format (printf, 2, 3))); |
| extern void fatal_abort(const char *, ...) |
| __attribute__((format (printf, 1, 2))) __attribute__((noreturn)); |
| extern void fatal(const char *, ...) |
| __attribute__((format (printf, 1, 2))) __attribute__((noreturn)); |
| int error(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| void warning(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| void slurm_info(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| void slurm_verbose(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| |
| extern const char plugin_type[]; |
| |
| #ifdef SLURM_PLUGIN_DEBUG |
| /* |
| * Print plugins with the plugin_type and func |
| */ |
| #define format_print(l, fmt, ...) \ |
| do { \ |
| if (get_log_level() >= l) \ |
| log_var(l, "%s: %s: "fmt, plugin_type, \ |
| __func__, ##__VA_ARGS__); \ |
| } while (0) |
| #else |
| /* |
| * Normal log messages |
| */ |
| #define format_print(l, fmt, ...) \ |
| do { \ |
| if (get_log_level() >= l) \ |
| log_var(l, fmt, ##__VA_ARGS__); \ |
| } while (0) |
| #endif //SLURM_PLUGIN_DEBUG |
| |
| #define info(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define verbose(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_VERBOSE, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define debug(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define debug2(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_DEBUG2, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define debug3(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_DEBUG3, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define debug4(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_DEBUG4, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| #define debug5(fmt, ...) \ |
| do { \ |
| format_print(LOG_LEVEL_DEBUG5, fmt, ##__VA_ARGS__);\ |
| } while (0) |
| |
| |
| /* |
| * Like above logging messages, but prepend "sched: " to the log entry |
| * and route the message into the sched_log if enabled. |
| */ |
| void sched_error(const char *, ...) __attribute__((format(printf, 1, 2))); |
| void sched_info(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| void sched_verbose(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| #define sched_debug(fmt, ...) \ |
| do { \ |
| if (get_sched_log_level() >= LOG_LEVEL_DEBUG) \ |
| sched_log_var(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__); \ |
| } while (0) |
| #define sched_debug2(fmt, ...) \ |
| do { \ |
| if (get_sched_log_level() >= LOG_LEVEL_DEBUG2) \ |
| sched_log_var(LOG_LEVEL_DEBUG2, fmt, ##__VA_ARGS__); \ |
| } while (0) |
| #define sched_debug3(fmt, ...) \ |
| do { \ |
| if (get_sched_log_level() >= LOG_LEVEL_DEBUG3) \ |
| sched_log_var(LOG_LEVEL_DEBUG3, fmt, ##__VA_ARGS__); \ |
| } while (0) |
| |
| /* |
| * Print at the same log level as error(), but without prefixing the message |
| * with "error: ". Useful to report back to srun commands from SPANK plugins, |
| * as info() will only go to the logs. |
| */ |
| void spank_log(const char *, ...) __attribute__ ((format (printf, 1, 2))); |
| |
| |
| /* |
| * Used to print log messages only when a specific DEBUG_FLAG_* option has |
| * been enabled. Automatically prepends 'DEBUG_FLAG_' to the flag option name |
| * to save space. E.g., to print a message only when DEBUG_FLAG_STEPS is |
| * enabled, call `log_flag(STEPS, "%s: my important message", __func__);`. |
| * |
| * As this is implemented in a macro, this is no slower than the equivalent |
| * conditional check. |
| */ |
| #define log_flag(flag, fmt, ...) \ |
| do { \ |
| if (slurm_conf.debug_flags & DEBUG_FLAG_##flag) \ |
| format_print(LOG_LEVEL_VERBOSE, #flag ": " fmt, \ |
| ##__VA_ARGS__); \ |
| } while (0) |
| |
| /* |
| * Log data as hex dump (use log_flag_hex() instead) |
| * IN data - ptr to data |
| * IN len - number of bytes pointed by data |
| * IN start - starting byte offset |
| * IN end - end byte offset |
| * IN fmt - message to prepend to hex dump |
| */ |
| extern void _log_flag_hex(const void *data, size_t len, ssize_t start, |
| ssize_t end, const char *fmt, ...); |
| |
| /* |
| * Log data as hex dump |
| * IN data - ptr to data |
| * IN len - number of bytes pointed by data |
| * IN fmt - message to prepend to hex dump |
| */ |
| #define log_flag_hex(flag, data, len, fmt, ...) \ |
| do { \ |
| if (slurm_conf.debug_flags & DEBUG_FLAG_##flag) \ |
| _log_flag_hex(data, len, -1, -1, \ |
| #flag ": " fmt, ##__VA_ARGS__); \ |
| } while (0) |
| /* |
| * Log range of bytes from data as hex dump |
| * IN data - ptr to data |
| * IN len - number of bytes pointed by data |
| * IN start - starting byte offset |
| * IN end - end byte offset |
| * IN fmt - message to prepend to hex dump |
| */ |
| #define log_flag_hex_range(flag, data, len, start, end, fmt, ...) \ |
| do { \ |
| if (slurm_conf.debug_flags & DEBUG_FLAG_##flag) \ |
| _log_flag_hex(data, len, start, end, \ |
| #flag ": " fmt, ##__VA_ARGS__); \ |
| } while (0) |
| |
| #endif /* !_LOG_H */ |