NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
logging.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <errno.h>
31#include <stdarg.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <string.h>
35#include <time.h>
36#include <unistd.h>
37#include "date.h"
38#include "file.h"
39#include "logging2.h"
40#include "memory.h"
41#include "message.h"
42#include "queue.h"
43#include "string2.h"
44
45static const char *LevelAbbr = "PEWM12345N";
46
53
54static FILE *LogFileFP = NULL;
55static char *LogFileName = NULL;
56static int LogFileLevel = 0;
57static char *LogFileVersion = NULL;
58
62static struct LogLineList LogQueue = STAILQ_HEAD_INITIALIZER(LogQueue);
63
64static int LogQueueCount = 0;
65static int LogQueueMax = 0;
66
77static const char *timestamp(time_t stamp)
78{
79 static char buf[23] = { 0 };
80 static time_t last = 0;
81
82 if (stamp == 0)
83 stamp = mutt_date_now();
84
85 if (stamp != last)
86 {
87 mutt_date_localtime_format(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", stamp);
88 last = stamp;
89 }
90
91 return buf;
92}
93
98void log_file_close(bool verbose)
99{
100 if (!LogFileFP)
101 return;
102
103 fprintf(LogFileFP, "[%s] Closing log.\n", timestamp(0));
104 fprintf(LogFileFP, "# vim: syntax=neomuttlog\n");
106 if (verbose)
107 mutt_message(_("Closed log file: %s"), LogFileName);
108}
109
119int log_file_open(bool verbose)
120{
121 if (!LogFileName)
122 return -1;
123
124 if (LogFileFP)
125 log_file_close(false);
126
128 return -1;
129
131 if (!LogFileFP)
132 return -1;
133 setvbuf(LogFileFP, NULL, _IOLBF, 0);
134
135 fprintf(LogFileFP, "[%s] NeoMutt%s debugging at level %d\n", timestamp(0),
137 if (verbose)
138 mutt_message(_("Debugging at level %d to file '%s'"), LogFileLevel, LogFileName);
139 return 0;
140}
141
149int log_file_set_filename(const char *file, bool verbose)
150{
151 if (!file)
152 return -1;
153
154 /* also handles both being NULL */
155 if (mutt_str_equal(LogFileName, file))
156 return 0;
157
159
160 if (!LogFileName)
161 log_file_close(verbose);
162
163 return log_file_open(verbose);
164}
165
175int log_file_set_level(enum LogLevel level, bool verbose)
176{
177 if ((level < LL_MESSAGE) || (level >= LL_MAX))
178 return -1;
179
180 if (level == LogFileLevel)
181 return 0;
182
183 LogFileLevel = level;
184
185 if (level == LL_MESSAGE)
186 {
187 log_file_close(verbose);
188 }
189 else if (LogFileFP)
190 {
191 if (verbose)
192 mutt_message(_("Logging at level %d to file '%s'"), LogFileLevel, LogFileName);
193 fprintf(LogFileFP, "[%s] NeoMutt%s debugging at level %d\n", timestamp(0),
195 }
196 else
197 {
198 log_file_open(verbose);
199 }
200
201 if (LogFileLevel >= LL_DEBUG5)
202 {
203 fprintf(LogFileFP, "\n"
204 "WARNING:\n"
205 " Logging at this level can reveal personal information.\n"
206 " Review the log carefully before posting in bug reports.\n"
207 "\n");
208 }
209
210 return 0;
211}
212
220void log_file_set_version(const char *version)
221{
223}
224
230{
231 return LogFileFP;
232}
233
245int log_disp_file(time_t stamp, const char *file, int line, const char *function,
246 enum LogLevel level, const char *format, ...)
247{
248 if (!LogFileFP || (level < LL_PERROR) || (level > LogFileLevel))
249 return 0;
250
251 int rc = 0;
252 int err = errno;
253
254 if (!function)
255 function = "UNKNOWN";
256
257 rc += fprintf(LogFileFP, "[%s]<%c> %s() ", timestamp(stamp), LevelAbbr[level + 3], function);
258
259 va_list ap;
260 va_start(ap, format);
261 rc += vfprintf(LogFileFP, format, ap);
262 va_end(ap);
263
264 if (level == LL_PERROR)
265 {
266 fprintf(LogFileFP, ": %s\n", strerror(err));
267 }
268 else if (level <= LL_MESSAGE)
269 {
270 fputs("\n", LogFileFP);
271 rc++;
272 }
273
274 return rc;
275}
276
284int log_queue_add(struct LogLine *ll)
285{
286 if (!ll)
287 return -1;
288
289 STAILQ_INSERT_TAIL(&LogQueue, ll, entries);
290
291 if ((LogQueueMax > 0) && (LogQueueCount >= LogQueueMax))
292 {
293 ll = STAILQ_FIRST(&LogQueue);
294 STAILQ_REMOVE_HEAD(&LogQueue, entries);
295 FREE(&ll->message);
296 FREE(&ll);
297 }
298 else
299 {
301 }
302 return LogQueueCount;
303}
304
312{
313 if (size < 0)
314 size = 0;
315 LogQueueMax = size;
316}
317
324{
325 struct LogLine *ll = NULL;
326 struct LogLine *tmp = NULL;
327
328 STAILQ_FOREACH_SAFE(ll, &LogQueue, entries, tmp)
329 {
330 STAILQ_REMOVE(&LogQueue, ll, LogLine, entries);
331 FREE(&ll->message);
332 FREE(&ll);
333 }
334
335 LogQueueCount = 0;
336}
337
346{
347 struct LogLine *ll = NULL;
348 STAILQ_FOREACH(ll, &LogQueue, entries)
349 {
350 disp(ll->time, ll->file, ll->line, ll->function, ll->level, "%s", ll->message);
351 }
352
354}
355
366int log_queue_save(FILE *fp)
367{
368 if (!fp)
369 return 0;
370
371 char buf[32] = { 0 };
372 int count = 0;
373 struct LogLine *ll = NULL;
374 STAILQ_FOREACH(ll, &LogQueue, entries)
375 {
376 mutt_date_localtime_format(buf, sizeof(buf), "%H:%M:%S", ll->time);
377 fprintf(fp, "[%s]<%c> %s", buf, LevelAbbr[ll->level + 3], ll->message);
378 if (ll->level <= LL_MESSAGE)
379 fputs("\n", fp);
380 count++;
381 }
382
383 return count;
384}
385
397int log_disp_queue(time_t stamp, const char *file, int line, const char *function,
398 enum LogLevel level, const char *format, ...)
399{
400 char buf[LOG_LINE_MAX_LEN] = { 0 };
401 int err = errno;
402
403 va_list ap;
404 va_start(ap, format);
405 int rc = vsnprintf(buf, sizeof(buf), format, ap);
406 va_end(ap);
407
408 if (level == LL_PERROR)
409 {
410 if ((rc >= 0) && (rc < sizeof(buf)))
411 rc += snprintf(buf + rc, sizeof(buf) - rc, ": %s", strerror(err));
412 level = LL_ERROR;
413 }
414
415 struct LogLine *ll = mutt_mem_calloc(1, sizeof(*ll));
416 ll->time = (stamp != 0) ? stamp : mutt_date_now();
417 ll->file = file;
418 ll->line = line;
419 ll->function = function;
420 ll->level = level;
421 ll->message = mutt_str_dup(buf);
422
423 log_queue_add(ll);
424
425 return rc;
426}
427
440int log_disp_terminal(time_t stamp, const char *file, int line, const char *function,
441 enum LogLevel level, const char *format, ...)
442{
443 char buf[LOG_LINE_MAX_LEN] = { 0 };
444
445 va_list ap;
446 va_start(ap, format);
447 int rc = vsnprintf(buf, sizeof(buf), format, ap);
448 va_end(ap);
449
450 log_disp_file(stamp, file, line, function, level, "%s", buf);
451
452 if ((level < LL_PERROR) || (level > LL_MESSAGE))
453 return 0;
454
455 FILE *fp = (level < LL_MESSAGE) ? stderr : stdout;
456 int err = errno;
457 int colour = 0;
458 bool tty = (isatty(fileno(fp)) == 1);
459
460 if (tty)
461 {
462 switch (level)
463 {
464 case LL_PERROR:
465 case LL_ERROR:
466 colour = 31;
467 break;
468 case LL_WARNING:
469 colour = 33;
470 break;
471 case LL_MESSAGE:
472 default:
473 break;
474 }
475 }
476
477 if (colour > 0)
478 rc += fprintf(fp, "\033[1;%dm", colour); // Escape
479
480 fputs(buf, fp);
481
482 if (level == LL_PERROR)
483 rc += fprintf(fp, ": %s", strerror(err));
484
485 if (colour > 0)
486 rc += fprintf(fp, "\033[0m"); // Escape
487
488 rc += fprintf(fp, "\n");
489
490 return rc;
491}
492
496int log_disp_null(time_t stamp, const char *file, int line, const char *function,
497 enum LogLevel level, const char *format, ...)
498{
499 return 0;
500}
Time and date handling routines.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
File management functions.
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:397
int log_disp_null(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Discard log lines - Implements log_dispatcher_t -.
Definition: logging.c:496
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:245
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Save a log line to the terminal - Implements log_dispatcher_t -.
Definition: logging.c:440
log_dispatcher_t MuttLogger
The log dispatcher -.
Definition: logging.c:52
#define mutt_message(...)
Definition: logging2.h:91
Logging Dispatcher.
int(* log_dispatcher_t)(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...) __attribute__((__format__(__printf__
Definition: logging2.h:69
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_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ LL_MAX
Definition: logging2.h:50
#define LOG_LINE_MAX_LEN
Log lines longer than this will be truncated.
Definition: logging2.h:32
int log_file_open(bool verbose)
Start logging to a file.
Definition: logging.c:119
static FILE * LogFileFP
Log file handle.
Definition: logging.c:54
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:323
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:311
int log_file_set_level(enum LogLevel level, bool verbose)
Set the logging level.
Definition: logging.c:175
static struct LogLineList LogQueue
In-memory list of log lines.
Definition: logging.c:62
bool log_file_running(void)
Is the log file running?
Definition: logging.c:229
static char * LogFileVersion
Program version.
Definition: logging.c:57
static int LogQueueMax
Maximum number of entries in the log queue.
Definition: logging.c:65
static const char * timestamp(time_t stamp)
Create a YYYY-MM-DD HH:MM:SS timestamp.
Definition: logging.c:77
static const char * LevelAbbr
Abbreviations of logging level names.
Definition: logging.c:45
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:345
static int LogQueueCount
Number of entries currently in the log queue.
Definition: logging.c:64
static int LogFileLevel
Log file level.
Definition: logging.c:56
int log_queue_save(FILE *fp)
Save the contents of the queue to a temporary file.
Definition: logging.c:366
static char * LogFileName
Log file name.
Definition: logging.c:55
void log_file_close(bool verbose)
Close the log file.
Definition: logging.c:98
int log_file_set_filename(const char *file, bool verbose)
Set the filename for the log.
Definition: logging.c:149
int log_queue_add(struct LogLine *ll)
Add a LogLine to the queue.
Definition: logging.c:284
void log_file_set_version(const char *version)
Set the program's version number.
Definition: logging.c:220
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
Memory management wrappers.
#define FREE(x)
Definition: memory.h:45
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:924
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
Message logging.
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define STAILQ_REMOVE_HEAD(head, field)
Definition: queue.h:422
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:389
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
String manipulation functions.
#define NONULL(x)
Definition: string2.h:37
A Log line.
Definition: logging2.h:78
const char * file
Source file.
Definition: logging2.h:80
char * message
Message to be logged.
Definition: logging2.h:84
const char * function
C function.
Definition: logging2.h:82
int line
Line number in source file.
Definition: logging2.h:81
enum LogLevel level
Log level, e.g. LL_DEBUG1.
Definition: logging2.h:83
time_t time
Timestamp of the message.
Definition: logging2.h:79