]> git.sesse.net Git - cubemap/blob - log.cpp
Clearer warnings in the cubemap.config.sample file about daemonizing and paths.
[cubemap] / log.cpp
1 #include "log.h"
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <syslog.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include <string>
10 #include <vector>
11
12 using namespace std;
13
14 // Yes, it's a bit ugly.
15 #define SYSLOG_FAKE_FILE (static_cast<FILE *>(NULL))
16
17 bool logging_started = false;
18 std::vector<FILE *> log_destinations;
19
20 void add_log_destination_file(const std::string &filename)
21 {
22         FILE *fp = fopen(filename.c_str(), "a");
23         if (fp == NULL) {
24                 perror(filename.c_str());
25                 return;
26         }
27
28         log_destinations.push_back(fp); 
29 }
30
31 void add_log_destination_console()
32 {
33         log_destinations.push_back(stderr);
34 }
35
36 void add_log_destination_syslog()
37 {
38         openlog("cubemap", LOG_PID, LOG_DAEMON);
39         log_destinations.push_back(SYSLOG_FAKE_FILE);
40 }
41
42 void start_logging()
43 {
44         logging_started = true;
45 }
46
47 void shut_down_logging()
48 {
49         for (size_t i = 0; i < log_destinations.size(); ++i) {
50                 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
51                         closelog();
52                 } else if (log_destinations[i] != stderr) {
53                         if (fclose(log_destinations[i]) != 0) {
54                                 perror("fclose");
55                         }
56                 }
57         }
58         log_destinations.clear();
59         logging_started = false;
60 }
61
62 void log(LogLevel log_level, const char *fmt, ...)
63 {
64         char formatted_msg[4096];
65         va_list ap;
66         va_start(ap, fmt);
67         vsnprintf(formatted_msg, sizeof(formatted_msg), fmt, ap);
68         va_end(ap);
69
70         const char *log_level_str;
71         int syslog_level;
72
73         switch (log_level) {
74         case INFO:
75                 log_level_str = "INFO:    ";
76                 syslog_level = LOG_INFO;
77                 break;
78         case WARNING:
79                 log_level_str = "WARNING: ";
80                 syslog_level = LOG_WARNING;
81                 break;
82         case ERROR:
83                 log_level_str = "ERROR:   ";
84                 syslog_level = LOG_ERR;
85                 break;
86         default:
87                 assert(false);
88         }
89
90         // Log to stderr if logging hasn't been set up yet. Note that this means
91         // that such messages will come even if there are no “error_log” lines.
92         if (!logging_started) {
93                 fprintf(stderr, "%s%s\n", log_level_str, formatted_msg);
94                 return;
95         }
96
97         for (size_t i = 0; i < log_destinations.size(); ++i) {
98                 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
99                         syslog(syslog_level, "%s", formatted_msg);
100                 } else {
101                         int err = fprintf(log_destinations[i], "%s%s\n", log_level_str, formatted_msg);
102                         if (err < 0) {
103                                 perror("fprintf");
104                         }
105                         if (log_destinations[i] != stderr) {
106                                 fflush(log_destinations[i]);
107                         }
108                 }
109         }
110 }
111
112 void log_perror(const char *msg)
113 {
114         char errbuf[4096];
115         log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
116 }