NeoMutt  2024-04-25-97-g7d2481
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mutt_logging.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <errno.h>
32#include <stdarg.h>
33#include <stdbool.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <string.h>
37#include <time.h>
38#include "mutt/lib.h"
39#include "config/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "mutt_logging.h"
43#include "color/lib.h"
44#include "globals.h"
45#include "muttlib.h"
46
47static uint64_t LastError = 0;
48
49static char *CurrentFile = NULL;
50static const int NumOfLogs = 5;
51
52#define S_TO_MS 1000L
53
59static void error_pause(void)
60{
61 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
62 const uint64_t elapsed = mutt_date_now_ms() - LastError;
63 const uint64_t sleep = c_sleep_time * S_TO_MS;
64 if ((LastError == 0) || (elapsed >= sleep))
65 return;
66
68 mutt_date_sleep_ms(sleep - elapsed);
69}
70
75{
76 /* Make sure the error message has had time to be read */
77 if (OptMsgErr)
79
80 ErrorBufMessage = false;
81 if (!OptNoCurses)
83}
84
88int log_disp_curses(time_t stamp, const char *file, int line, const char *function,
89 enum LogLevel level, const char *format, ...)
90{
91 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
92 if (level > c_debug_level)
93 return 0;
94
95 char buf[LOG_LINE_MAX_LEN] = { 0 };
96
97 va_list ap;
98 va_start(ap, format);
99 int rc = vsnprintf(buf, sizeof(buf), format, ap);
100 va_end(ap);
101
102 if ((level == LL_PERROR) && (rc >= 0) && (rc < sizeof(buf)))
103 {
104 char *buf2 = buf + rc;
105 int len = sizeof(buf) - rc;
106 const char *p = strerror(errno);
107 if (!p)
108 p = _("unknown error");
109
110 rc += snprintf(buf2, len, ": %s (errno = %d)", p, errno);
111 }
112
113 const bool dupe = (mutt_str_equal(buf, ErrorBuf));
114 if (!dupe)
115 {
116 /* Only log unique messages */
117 log_disp_file(stamp, file, line, function, level, "%s", buf);
118 if (stamp == 0)
119 log_disp_queue(stamp, file, line, function, level, "%s", buf);
120 }
121
122 /* Don't display debugging message on screen */
123 if (level > LL_MESSAGE)
124 return 0;
125
126 /* Only pause if this is a message following an error */
127 if ((level > LL_ERROR) && OptMsgErr && !dupe)
128 error_pause();
129
130 mutt_str_copy(ErrorBuf, buf, sizeof(ErrorBuf));
131 ErrorBufMessage = true;
132
133 if (!OptKeepQuiet)
134 {
135 enum ColorId cid = MT_COLOR_NORMAL;
136 switch (level)
137 {
138 case LL_ERROR:
139 mutt_beep(false);
140 cid = MT_COLOR_ERROR;
141 break;
142 case LL_WARNING:
143 cid = MT_COLOR_WARNING;
144 break;
145 default:
146 cid = MT_COLOR_MESSAGE;
147 break;
148 }
149
150 msgwin_set_text(NULL, ErrorBuf, cid);
151 }
152
153 if ((level <= LL_ERROR) && !dupe)
154 {
155 OptMsgErr = true;
157 }
158 else
159 {
160 OptMsgErr = false;
161 LastError = 0;
162 }
163
165 return rc;
166}
167
172{
173 char ver[64] = { 0 };
174 snprintf(ver, sizeof(ver), "-%s%s", PACKAGE_VERSION, GitVer);
176}
177
182{
183 log_file_close(false);
185}
186
195int mutt_log_set_file(const char *file)
196{
197 const char *const c_debug_file = cs_subset_path(NeoMutt->sub, "debug_file");
198 if (!mutt_str_equal(CurrentFile, c_debug_file))
199 {
200 struct Buffer *expanded = buf_pool_get();
201 buf_addstr(expanded, c_debug_file);
202 buf_expand_path(expanded);
203
204 const char *name = mutt_file_rotate(buf_string(expanded), NumOfLogs);
205 buf_pool_release(&expanded);
206 if (!name)
207 return -1;
208
209 log_file_set_filename(name, false);
210 FREE(&name);
211 mutt_str_replace(&CurrentFile, c_debug_file);
212 }
213
214 cs_subset_str_string_set(NeoMutt->sub, "debug_file", file, NULL);
215
216 return 0;
217}
218
226int mutt_log_set_level(enum LogLevel level, bool verbose)
227{
228 if (!CurrentFile)
229 {
230 const char *const c_debug_file = cs_subset_path(NeoMutt->sub, "debug_file");
231 mutt_log_set_file(c_debug_file);
232 }
233
234 if (log_file_set_level(level, verbose) != 0)
235 return -1;
236
237 cs_subset_str_native_set(NeoMutt->sub, "debug_level", level, NULL);
238 return 0;
239}
240
249{
250 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
251 if (c_debug_level < 1)
252 return 0;
253
254 if (log_file_running())
255 return 0;
256
257 const char *const c_debug_file = cs_subset_path(NeoMutt->sub, "debug_file");
258 mutt_log_set_file(c_debug_file);
259
260 /* This will trigger the file creation */
261 if (log_file_set_level(c_debug_level, true) < 0)
262 return -1;
263
264 return 0;
265}
266
270int level_validator(const struct ConfigSet *cs, const struct ConfigDef *cdef,
271 intptr_t value, struct Buffer *err)
272{
273 if ((value < 0) || (value >= LL_MAX))
274 {
275 buf_printf(err, _("Invalid value for option %s: %ld"), cdef->name, (long) value);
276 return CSR_ERR_INVALID;
277 }
278
279 return CSR_SUCCESS;
280}
281
286{
287 if (nc->event_type != NT_CONFIG)
288 return 0;
289 if (!nc->event_data)
290 return -1;
291
292 struct EventConfig *ev_c = nc->event_data;
293
294 if (mutt_str_equal(ev_c->name, "debug_file"))
295 {
296 const char *const c_debug_file = cs_subset_path(NeoMutt->sub, "debug_file");
297 mutt_log_set_file(c_debug_file);
298 }
299 else if (mutt_str_equal(ev_c->name, "debug_level"))
300 {
301 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
302 mutt_log_set_level(c_debug_level, true);
303 }
304 else
305 {
306 return 0;
307 }
308
309 mutt_debug(LL_DEBUG5, "log done\n");
310 return 0;
311}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
Color and attribute parsing.
ColorId
List of all colored objects.
Definition: color.h:40
@ MT_COLOR_MESSAGE
Informational message.
Definition: color.h:57
@ MT_COLOR_ERROR
Error message.
Definition: color.h:51
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:59
@ MT_COLOR_WARNING
Warning messages.
Definition: color.h:81
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:168
Convenience wrapper for the config headers.
#define CSR_ERR_INVALID
Value hasn't been set.
Definition: set.h:38
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
Convenience wrapper for the core headers.
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:78
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:68
const char * mutt_file_rotate(const char *path, int count)
Rotate a set of numbered files.
Definition: file.c:546
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:66
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: globals.c:72
char ErrorBuf[1024]
Copy of the last error message.
Definition: globals.c:36
bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: globals.c:67
bool ErrorBufMessage
true if the last message was an error
Definition: globals.c:35
Global variables.
const char * GitVer
int level_validator(const struct ConfigSet *cs, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Validate the "debug_level" config variable - Implements ConfigDef::validator() -.
Definition: mutt_logging.c:270
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Save a log line to an internal queue - Implements log_dispatcher_t -.
Definition: logging.c:398
int log_disp_file(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Save a log line to a file - Implements log_dispatcher_t -.
Definition: logging.c:246
int log_disp_curses(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Display a log line in the message line - Implements log_dispatcher_t -.
Definition: mutt_logging.c:88
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: mutt_logging.c:285
Convenience wrapper for the gui headers.
LogLevel
Names for the Logging Levels.
Definition: logging2.h:38
@ LL_ERROR
Log error.
Definition: logging2.h:40
@ LL_PERROR
Log perror (using errno)
Definition: logging2.h:39
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_WARNING
Log warning.
Definition: logging2.h:41
@ LL_MESSAGE
Log informational message.
Definition: logging2.h:42
@ LL_MAX
Definition: logging2.h:50
#define LOG_LINE_MAX_LEN
Log lines longer than this will be truncated.
Definition: logging2.h:32
#define FREE(x)
Definition: memory.h:45
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:530
void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
Set the text for the Message Window.
Definition: msgwin.c:484
uint64_t mutt_date_now_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:465
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:983
Convenience wrapper for the library headers.
int log_file_set_level(enum LogLevel level, bool verbose)
Set the logging level.
Definition: logging.c:176
bool log_file_running(void)
Is the log file running?
Definition: logging.c:230
void log_file_close(bool verbose)
Close the log file.
Definition: logging.c:99
int log_file_set_filename(const char *file, bool verbose)
Set the filename for the log.
Definition: logging.c:150
void log_file_set_version(const char *version)
Set the program's version number.
Definition: logging.c:221
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:581
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
static const int NumOfLogs
How many log files to rotate.
Definition: mutt_logging.c:50
int mutt_log_set_level(enum LogLevel level, bool verbose)
Change the logging level.
Definition: mutt_logging.c:226
int mutt_log_set_file(const char *file)
Change the logging file.
Definition: mutt_logging.c:195
static uint64_t LastError
Time of the last error message (in milliseconds since the Unix epoch)
Definition: mutt_logging.c:47
#define S_TO_MS
Definition: mutt_logging.c:52
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:181
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:248
static void error_pause(void)
Wait for an error message to be read.
Definition: mutt_logging.c:59
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:171
static char * CurrentFile
The previous log file name.
Definition: mutt_logging.c:49
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:633
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
String manipulation buffer.
Definition: buffer.h:36
Definition: set.h:64
const char * name
User-visible name.
Definition: set.h:65
Container for lots of config items.
Definition: set.h:252
A config-change event.
Definition: subset.h:71
const char * name
Name of config item that changed.
Definition: subset.h:73
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Data passed to a notification function.
Definition: observer.h:34
void * event_data
Data from notify_send()
Definition: observer.h:38
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:297
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:386