1 /*****************************************************************************\
2  *  log.h - configurable logging for slurm: log to file, stderr and/or syslog.
3  *****************************************************************************
4  *  Copyright (C) 2002-2007 The Regents of the University of California.
5  *  Copyright (C) 2008-2010 Lawrence Livermore National Security.
6  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7  *  Written by Mark Grondona <mgrondona@llnl.gov>
8  *  CODE-OCEC-09-009. All rights reserved.
9  *
10  *  Much of this code was derived or adapted from the log.c component of
11  *  openssh which contains the following notices:
12  *****************************************************************************
13  * Author: Tatu Ylonen <ylo@cs.hut.fi>
14  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
15  *                    All rights reserved
16  *
17  * As far as I am concerned, the code I have written for this software
18  * can be used freely for any purpose.  Any derived versions of this
19  * software must be clearly marked as such, and if the derived work is
20  * incompatible with the protocol description in the RFC file, it must be
21  * called by a name other than "ssh" or "Secure Shell".
22  *****************************************************************************
23  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the above copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
35  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
37  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
38  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
39  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
40  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
41  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 \*****************************************************************************/
45 
46 #ifndef _LOG_H
47 #define _LOG_H
48 
49 #include <syslog.h>
50 #include <stdio.h>
51 
52 #include "src/common/macros.h"
53 #include "src/common/cbuf.h"
54 
55 /* supported syslog facilities and levels */
56 typedef enum {
57 	SYSLOG_FACILITY_DAEMON = 	LOG_DAEMON,
58 	SYSLOG_FACILITY_USER = 		LOG_USER,
59 	SYSLOG_FACILITY_AUTH = 		LOG_AUTH,
60 #ifdef LOG_AUTHPRIV
61 	SYSLOG_FACILITY_AUTHPRIV =	LOG_AUTHPRIV,
62 #endif
63 	SYSLOG_FACILITY_LOCAL0 =	LOG_LOCAL0,
64 	SYSLOG_FACILITY_LOCAL1 =	LOG_LOCAL1,
65 	SYSLOG_FACILITY_LOCAL2 =	LOG_LOCAL2,
66 	SYSLOG_FACILITY_LOCAL3 =	LOG_LOCAL3,
67 	SYSLOG_FACILITY_LOCAL4 =	LOG_LOCAL4,
68 	SYSLOG_FACILITY_LOCAL5 =	LOG_LOCAL5,
69 	SYSLOG_FACILITY_LOCAL6 =	LOG_LOCAL6,
70 	SYSLOG_FACILITY_LOCAL7 =	LOG_LOCAL7
71 } 	log_facility_t;
72 
73 /*
74  * log levels, logging will occur at or below the selected level
75  * QUIET disable logging completely.
76  */
77 typedef enum {
78 	LOG_LEVEL_QUIET = 0,
79 	LOG_LEVEL_FATAL,
80 	LOG_LEVEL_ERROR,
81 	LOG_LEVEL_INFO,
82 	LOG_LEVEL_VERBOSE,
83 	LOG_LEVEL_DEBUG,
84 	LOG_LEVEL_DEBUG2,
85 	LOG_LEVEL_DEBUG3,
86 	LOG_LEVEL_DEBUG4,
87 	LOG_LEVEL_DEBUG5,
88 	LOG_LEVEL_END
89 }	log_level_t;
90 
91 
92 /*
93  * log options: Each of stderr, syslog, and logfile can have a different level
94  */
95 typedef struct {
96 	log_level_t stderr_level;   /* max level to log to stderr            */
97 	log_level_t syslog_level;   /* max level to log to syslog            */
98 	log_level_t logfile_level;  /* max level to log to logfile           */
99 	bool prefix_level;          /* prefix level (e.g. "debug: ") if true */
100 	bool buffered;              /* use internal buffer to never block    */
101 } 	log_options_t;
102 
103 extern char *slurm_prog_name;
104 
105 /* some useful initializers for log_options_t
106  */
107 #define LOG_OPTS_INITIALIZER	\
108 	{ LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_INFO, 1, 0 }
109 
110 #define LOG_OPTS_SYSLOG_DEFAULT	\
111 	{ LOG_LEVEL_QUIET, LOG_LEVEL_INFO, LOG_LEVEL_QUIET, 1, 0 }
112 
113 #define LOG_OPTS_STDERR_ONLY	\
114 	{ LOG_LEVEL_INFO,  LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, 1, 0 }
115 
116 #define SCHEDLOG_OPTS_INITIALIZER	\
117 	{ LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, LOG_LEVEL_QUIET, 0, 1 }
118 
119 
120 /* Functions for filling in a char buffer with a timestamp. */
121 size_t rfc2822_timestamp(char *, size_t);
122 size_t log_timestamp(char *, size_t);
123 
124 
125 /*
126  * initialize log module (called only once)
127  *
128  * example:
129  *
130  * To initialize log module to print fatal messages to stderr, and
131  * all messages up to and including info() to syslog:
132  *
133  * log_options_t logopts = LOG_OPTS_INITIALIZER;
134  * logopts.stderr_level  = LOG_LEVEL_FATAL;
135  * logopts.syslog_level  = LOG_LEVEL_INFO;
136  *
137  * rc = log_init(argv[0], logopts, SYSLOG_FACILITY_DAEMON, NULL);
138  *
139  * log function automatically takes the basename() of argv0.
140  */
141 int log_init(char *argv0, log_options_t opts,
142 	      log_facility_t fac, char *logfile);
143 
144 /*
145  * initialize scheduler log module (called only once)
146  */
147 int sched_log_init(char *argv0, log_options_t opts, log_facility_t fac,
148 		   char *logfile);
149 
150 /* reinitialize log module.
151  * Keep same log options as previously initialized log, but reinit mutex
152  * that protects the log. This call is needed after a fork() in a threaded
153  * program
154  */
155 void log_reinit(void);
156 
157 /*
158  * Close log and free associated memory
159  */
160 void log_fini(void);
161 
162 /*
163  * Close scheduler log and free associated memory
164  */
165 void sched_log_fini(void);
166 
167 /* Alter log facility, options are like log_init() above, except that
168  * an argv0 argument is not passed.
169  *
170  * This function may be called multiple times.
171  */
172 int log_alter(log_options_t opts, log_facility_t fac, char *logfile);
173 
174 /* Alter log facility, options are like log_alter() above, except that
175  * an the file pointer is sent in instead of a filename.
176  *
177  * This function may only be called once.
178  */
179 int log_alter_with_fp(log_options_t opt, log_facility_t fac, FILE *fp_in);
180 
181 /* Sched alter log facility, options are like sched_log_init() above,
182  * except that an argv0 argument is not passed.
183  *
184  * This function may be called multiple times.
185  */
186 int sched_log_alter(log_options_t opts, log_facility_t fac, char *logfile);
187 
188 /* Set prefix for log file entries
189  * (really only useful for slurmd at this point).
190  * Note: will store pfx internally, do not use after this call.
191  */
192 void log_set_fpfx(char **pfx);
193 
194 /*
195  * (re)set argv0 string prepended to all log messages
196  */
197 void log_set_argv0(char *pfx);
198 
199 /* Return the FILE * of the current logfile (or stderr if not logging to
200  * a file, but NOT both). Also see log_oom() below. */
201 FILE *log_fp(void);
202 
203 /* Log out of memory without message buffering */
204 void log_oom(const char *file, int line, const char *func);
205 
206 /* Set the log timestamp format */
207 void log_set_timefmt(unsigned);
208 
209 /*
210  * Buffered log functions:
211  *
212  * log_has_data() returns true if there is data in the
213  * internal log buffer
214  */
215 bool log_has_data(void);
216 
217 /*
218  * log_flush() attempts to flush all data in the internal
219  * log buffer to the appropriate output stream.
220  */
221 void log_flush(void);
222 
223 /* log_set_debug_flags()
224  * Set or reset the debug flags based on the configuration
225  * file or the scontrol command.
226  */
227 extern void log_set_debug_flags(void);
228 
229 /* Return the highest LOG_LEVEL_* used for any logging mechanism.
230  * For example, if LOG_LEVEL_INFO is returned, we know that all verbose and
231  * debug type messages will be ignored. */
232 extern int get_log_level(void);
233 
234 /*
235  * Returns the greater of the sched_log_level or the log_level.
236  */
237 extern int get_sched_log_level(void);
238 
239 /*
240  * the following log a message to the log facility at the appropriate level:
241  *
242  * Messages do not need a newline!
243  *
244  * args are printf style with the following exceptions:
245  * %m expands to strerror(errno)
246  * %M expand to time stamp, format is configuration dependent
247  * %pJ expands to "JobId=XXXX" for the given job_ptr, with the appropriate
248  *     format for job arrays and hetjob components.
249  * %pS expands to "JobId=XXXX StepId=YYYY" for a given step_ptr.
250  * %t expands to strftime("%x %X") [ locally preferred short date/time ]
251  * %T expands to rfc2822 date time  [ "dd, Mon yyyy hh:mm:ss GMT offset" ]
252  */
253 
254 /*
255  * fatal() exits program
256  * error() returns SLURM_ERROR
257  */
258 void	log_var(const log_level_t, const char *, ...)
259 			__attribute__ ((format (printf, 2, 3)));
260 void	sched_log_var(const log_level_t, const char *, ...)
261 			__attribute__ ((format (printf, 2, 3)));
262 extern void fatal_abort(const char *, ...)
263 	__attribute__((format (printf, 1, 2))) __attribute__((noreturn));
264 extern void fatal(const char *, ...)
265 	__attribute__((format (printf, 1, 2))) __attribute__((noreturn));
266 int	error(const char *, ...) __attribute__ ((format (printf, 1, 2)));
267 void	info(const char *, ...) __attribute__ ((format (printf, 1, 2)));
268 void	verbose(const char *, ...) __attribute__ ((format (printf, 1, 2)));
269 #define debug(fmt, ...)						\
270 	do {								\
271 		if (get_log_level() >= LOG_LEVEL_DEBUG)			\
272 			log_var(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__);	\
273 	} while (0)
274 #define debug2(fmt, ...)						\
275 	do {								\
276 		if (get_log_level() >= LOG_LEVEL_DEBUG2)		\
277 			log_var(LOG_LEVEL_DEBUG2, fmt, ##__VA_ARGS__);	\
278 	} while (0)
279 /*
280  * Debug levels higher than debug3 are not written to stderr in the
281  * slurmstepd process after stderr is connected back to the client (srun).
282  */
283 #define debug3(fmt, ...)						\
284 	do {								\
285 		if (get_log_level() >= LOG_LEVEL_DEBUG3)		\
286 			log_var(LOG_LEVEL_DEBUG3, fmt, ##__VA_ARGS__);	\
287 	} while (0)
288 #define debug4(fmt, ...)						\
289 	do {								\
290 		if (get_log_level() >= LOG_LEVEL_DEBUG4)		\
291 			log_var(LOG_LEVEL_DEBUG4, fmt, ##__VA_ARGS__);	\
292 	} while (0)
293 #define debug5(fmt, ...)						\
294 	do {								\
295 		if (get_log_level() >= LOG_LEVEL_DEBUG5)		\
296 			log_var(LOG_LEVEL_DEBUG5, fmt, ##__VA_ARGS__);	\
297 	} while (0)
298 /*
299  * Like above logging messages, but prepend "sched: " to the log entry
300  * and route the message into the sched_log if enabled.
301  */
302 int	sched_error(const char *, ...) __attribute__ ((format (printf, 1, 2)));
303 void	sched_info(const char *, ...) __attribute__ ((format (printf, 1, 2)));
304 void	sched_verbose(const char *, ...) __attribute__ ((format (printf, 1, 2)));
305 #define sched_debug(fmt, ...)						\
306 	do {								\
307 		if (get_sched_log_level() >= LOG_LEVEL_DEBUG)		\
308 			sched_log_var(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__); \
309 	} while (0)
310 #define sched_debug2(fmt, ...)						\
311 	do {								\
312 		if (get_sched_log_level() >= LOG_LEVEL_DEBUG2)		\
313 			sched_log_var(LOG_LEVEL_DEBUG2, fmt, ##__VA_ARGS__); \
314 	} while (0)
315 #define sched_debug3(fmt, ...)						\
316 	do {								\
317 		if (get_sched_log_level() >= LOG_LEVEL_DEBUG3)		\
318 			sched_log_var(LOG_LEVEL_DEBUG3, fmt, ##__VA_ARGS__); \
319 	} while (0)
320 
321 /*
322  * Print at the same log level as error(), but without prefixing the message
323  * with "error: ". Useful to report back to srun commands from SPANK plugins,
324  * as info() will only go to the logs.
325  */
326 void spank_log(const char *, ...) __attribute__ ((format (printf, 1, 2)));
327 
328 
329 /*
330  * Used to print log messages only when a specific DEBUG_FLAG_* option has
331  * been enabled. Automatically prepends 'DEBUG_FLAG_' to the flag option name
332  * to save space. E.g., to print a message only when DEBUG_FLAG_STEPS is
333  * enabled, call `log_flag(STEPS, "%s: my important message", __func__);`.
334  *
335  * As this is implemented in a macro, this is no slower than the equivalent
336  * conditional check.
337  */
338 #define log_flag(flag, fmt, ...)					\
339 	do {								\
340 		if (slurmctld_conf.debug_flags & DEBUG_FLAG_##flag)	\
341 			log_var(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__);	\
342 	} while (0)
343 
344 #endif /* !_LOG_H */
345