NeoMutt  2018-07-16 +2481-68dcde
Teaching an old dog new tricks
DOXYGEN
mutt_logging.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdarg.h>
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include "mutt/mutt.h"
38 #include "config/lib.h"
39 #include "curs_lib.h"
40 #include "globals.h"
41 #include "mutt_curses.h"
42 #include "mutt_window.h"
43 #include "muttlib.h"
44 #include "options.h"
45 
46 size_t LastError = 0;
47 
48 short C_DebugLevel = 0;
49 char *C_DebugFile = NULL;
50 char *CurrentFile = NULL;
51 const int NumOfLogs = 5;
53 #define S_TO_MS 1000L
54 
60 static void error_pause(void)
61 {
62  const size_t elapsed = mutt_date_epoch_ms() - LastError;
63  const size_t sleep = C_SleepTime * S_TO_MS;
64  if ((LastError == 0) || (elapsed >= sleep))
65  return;
66 
67  mutt_refresh();
68  mutt_date_sleep_ms(sleep - elapsed);
69 }
70 
84 static const char *rotate_logs(const char *file, int count)
85 {
86  if (!file)
87  return NULL;
88 
89  char old_file[PATH_MAX];
90  char new_file[PATH_MAX];
91 
92  /* rotate the old debug logs */
93  for (count -= 2; count >= 0; count--)
94  {
95  snprintf(old_file, sizeof(old_file), "%s%d", file, count);
96  snprintf(new_file, sizeof(new_file), "%s%d", file, count + 1);
97 
98  mutt_expand_path(old_file, sizeof(old_file));
99  mutt_expand_path(new_file, sizeof(new_file));
100  rename(old_file, new_file);
101  }
102 
103  return mutt_str_strdup(old_file);
104 }
105 
110 {
111  /* Make sure the error message has had time to be read */
112  if (OptMsgErr)
113  error_pause();
114 
115  ErrorBufMessage = false;
116  if (!OptNoCurses)
118 }
119 
123 int log_disp_curses(time_t stamp, const char *file, int line,
124  const char *function, int level, ...)
125 {
126  if (level > C_DebugLevel)
127  return 0;
128 
129  char buf[1024];
130 
131  va_list ap;
132  va_start(ap, level);
133  const char *fmt = va_arg(ap, const char *);
134  int ret = vsnprintf(buf, sizeof(buf), fmt, ap);
135  va_end(ap);
136 
137  if (level == LL_PERROR)
138  {
139  char *buf2 = buf + ret;
140  int len = sizeof(buf) - ret;
141  char *p = strerror(errno);
142  if (!p)
143  p = _("unknown error");
144 
145  ret += snprintf(buf2, len, ": %s (errno = %d)", p, errno);
146  }
147 
148  const bool dupe = (strcmp(buf, ErrorBuf) == 0);
149  if (!dupe)
150  {
151  /* Only log unique messages */
152  log_disp_file(stamp, file, line, function, level, "%s", buf);
153  if (stamp == 0)
154  log_disp_queue(stamp, file, line, function, level, "%s", buf);
155  }
156 
157  /* Don't display debugging message on screen */
158  if (level > LL_MESSAGE)
159  return 0;
160 
161  /* Only pause if this is a message following an error */
162  if ((level > LL_ERROR) && OptMsgErr && !dupe)
163  error_pause();
164 
166  JUSTIFY_LEFT, 0, buf, sizeof(buf), false);
167  ErrorBufMessage = true;
168 
169  if (!OptKeepQuiet)
170  {
171  if (level == LL_ERROR)
172  BEEP();
175  NORMAL_COLOR;
177  mutt_refresh();
178  }
179 
180  if ((level <= LL_ERROR) && !dupe)
181  {
182  OptMsgErr = true;
184  }
185  else
186  {
187  OptMsgErr = false;
188  LastError = 0;
189  }
190 
191  return ret;
192 }
193 
197 void mutt_log_prep(void)
198 {
199  char ver[64];
200  snprintf(ver, sizeof(ver), "-%s%s", PACKAGE_VERSION, GitVer);
202 }
203 
207 void mutt_log_stop(void)
208 {
209  log_file_close(false);
210  FREE(&CurrentFile);
211 }
212 
222 int mutt_log_set_file(const char *file, bool verbose)
223 {
225  {
226  const char *name = rotate_logs(C_DebugFile, NumOfLogs);
227  if (!name)
228  return -1;
229 
230  log_file_set_filename(name, false);
231  FREE(&name);
233  }
234 
235  cs_str_string_set(Config, "debug_file", file, NULL);
236 
237  return 0;
238 }
239 
247 int mutt_log_set_level(int level, bool verbose)
248 {
249  if (!CurrentFile)
251 
252  if (log_file_set_level(level, verbose) != 0)
253  return -1;
254 
255  cs_str_native_set(Config, "debug_level", level, NULL);
256  return 0;
257 }
258 
266 int mutt_log_start(void)
267 {
268  if (C_DebugLevel < 1)
269  return 0;
270 
271  if (log_file_running())
272  return 0;
273 
275 
276  /* This will trigger the file creation */
277  if (log_file_set_level(C_DebugLevel, true) < 0)
278  return -1;
279 
280  return 0;
281 }
282 
292 int level_validator(const struct ConfigSet *cs, const struct ConfigDef *cdef,
293  intptr_t value, struct Buffer *err)
294 {
295  if ((value < 0) || (value >= LL_MAX))
296  {
297  mutt_buffer_printf(err, _("Invalid value for option %s: %ld"), cdef->name, value);
298  return CSR_ERR_INVALID;
299  }
300 
301  return CSR_SUCCESS;
302 }
303 
308 {
309  if (!nc)
310  return -1;
311 
312  struct EventConfig *ec = (struct EventConfig *) nc->event;
313 
314  if (mutt_str_strcmp(ec->name, "debug_file") == 0)
316  else if (mutt_str_strcmp(ec->name, "debug_level") == 0)
318 
319  return 0;
320 }
Log error.
Definition: logging.h:53
Container for lots of config items.
Definition: set.h:187
void log_file_close(bool verbose)
Close the log file.
Definition: logging.c:98
size_t LastError
Time of the last error message (in milliseconds since the Unix epoch)
Definition: mutt_logging.c:46
Define wrapper functions around Curses/Slang.
Left justify the text.
Definition: curs_lib.h:46
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:266
Data passed to a notification function.
Definition: observer.h:40
int level_validator(const struct ConfigSet *cs, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Validate the "debug_level" config variable.
Definition: mutt_logging.c:292
Window management.
GUI miscellaneous curses (window drawing) routines.
const int NumOfLogs
How many log files to rotate.
Definition: mutt_logging.c:51
int cs_str_string_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: set.c:627
#define NORMAL_COLOR
Definition: mutt_curses.h:239
WHERE short C_SleepTime
Config: Time to pause after certain info messages.
Definition: globals.h:155
int mutt_log_set_file(const char *file, bool verbose)
Change the logging file.
Definition: mutt_logging.c:222
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:107
Log perror (using errno)
Definition: logging.h:52
A config-change event.
Definition: set.h:199
String manipulation buffer.
Definition: buffer.h:33
char * CurrentFile
The previous log file name.
Definition: mutt_logging.c:50
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:40
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:46
intptr_t event
Send: event data.
Definition: observer.h:46
Definition: logging.h:63
Log informational message.
Definition: logging.h:55
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Config item definition.
Definition: set.h:153
void log_file_set_version(const char *version)
Set the program&#39;s version number.
Definition: logging.c:220
int log_file_set_filename(const char *file, bool verbose)
Set the filename for the log.
Definition: logging.c:148
Convenience wrapper for the config headers.
Hundreds of global variables to back the user variables.
Some miscellaneous functions.
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
const struct ConfigSet * cs
Config set.
Definition: set.h:201
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:95
const char * name
Definition: pgpmicalg.c:45
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to an internal queue - Implements log_dispatcher_t.
Definition: logging.c:408
const char * name
User-visible name.
Definition: set.h:155
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:109
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:46
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:94
const char * line
Definition: common.c:36
short C_DebugLevel
Config: Logging level for debug logs.
Definition: mutt_logging.c:48
bool log_file_running(void)
Is the log file running?
Definition: logging.c:229
#define CSR_ERR_INVALID
Value hasn&#39;t been set.
Definition: set.h:49
int log_disp_curses(time_t stamp, const char *file, int line, const char *function, int level,...)
Display a log line in the message line - Implements log_dispatcher_t.
Definition: mutt_logging.c:123
const char * GitVer
Informational message.
Definition: mutt_curses.h:137
#define PATH_MAX
Definition: mutt.h:52
#define BEEP()
Definition: mutt_curses.h:80
size_t mutt_date_epoch_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:419
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: globals.h:45
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: globals.h:44
#define S_TO_MS
Definition: mutt_logging.c:53
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:207
#define SET_COLOR(X)
Definition: mutt_curses.h:224
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
int mutt_window_mvaddstr(struct MuttWindow *win, int row, int col, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:202
char * C_DebugFile
Config: File to save debug logs.
Definition: mutt_logging.c:49
int log_disp_file(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to a file.
Definition: logging.c:254
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
int mutt_log_set_level(int level, bool verbose)
Change the logging level.
Definition: mutt_logging.c:247
Error message.
Definition: mutt_curses.h:132
WHERE bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: options.h:39
int log_file_set_level(int level, bool verbose)
Set the logging level.
Definition: logging.c:174
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:42
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:197
Handling of global boolean variables.
static void error_pause(void)
Wait for an error message to be read.
Definition: mutt_logging.c:60
WHERE bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program...
Definition: options.h:37
int mutt_log_observer(struct NotifyCallback *nc)
Listen for config changes affecting the log file - Implements observer_t()
Definition: mutt_logging.c:307
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:786
const char * name
Name of config item that changed.
Definition: set.h:203
static const char * rotate_logs(const char *file, int count)
Rotate a set of numbered files.
Definition: mutt_logging.c:84
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:1000
int cs_str_native_set(const struct ConfigSet *cs, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: set.c:772