20 // Yes, it's a bit ugly.
21 #define SYSLOG_FAKE_FILE (static_cast<FILE *>(nullptr))
23 bool logging_started = false;
24 vector<FILE *> log_destinations;
26 void add_log_destination_file(const string &filename)
28 FILE *fp = fopen(filename.c_str(), "ae");
30 perror(filename.c_str());
34 log_destinations.push_back(fp);
37 void add_log_destination_console()
39 log_destinations.push_back(stderr);
42 void add_log_destination_syslog()
44 openlog("cubemap", LOG_PID, LOG_DAEMON);
45 log_destinations.push_back(SYSLOG_FAKE_FILE);
50 logging_started = true;
53 void shut_down_logging()
55 for (size_t i = 0; i < log_destinations.size(); ++i) {
56 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
58 } else if (log_destinations[i] != stderr) {
59 if (fclose(log_destinations[i]) != 0) {
64 log_destinations.clear();
65 logging_started = false;
68 void log(LogLevel log_level, const char *fmt, ...)
70 char formatted_msg[4096];
73 vsnprintf(formatted_msg, sizeof(formatted_msg), fmt, ap);
76 time_t now = time(nullptr);
78 struct tm *ltime = localtime_r(&now, <);
80 if (ltime == nullptr) {
81 strcpy(timestamp, "???");
83 strftime(timestamp, sizeof(timestamp), "%a, %d %b %Y %T %z", ltime);
86 const char *log_level_str;
91 log_level_str = "INFO: ";
92 syslog_level = LOG_INFO;
95 log_level_str = "WARNING: ";
96 syslog_level = LOG_WARNING;
99 log_level_str = "ERROR: ";
100 syslog_level = LOG_ERR;
106 // Log to stderr if logging hasn't been set up yet. Note that this means
107 // that such messages will come even if there are no “error_log” lines.
108 if (!logging_started) {
109 fprintf(stderr, "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
113 for (size_t i = 0; i < log_destinations.size(); ++i) {
114 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
115 syslog(syslog_level, "%s", formatted_msg);
117 int err = fprintf(log_destinations[i], "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
121 if (log_destinations[i] != stderr) {
122 fflush(log_destinations[i]);
128 void log_perror(const char *msg)
131 log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
134 void log_tls_error(const char *msg, int tls_err)
137 case TLS_NEED_MORE_DATA:
138 log(ERROR, "%s: Need more data (TLS)", msg);
140 case TLS_GENERIC_ERROR:
141 log(ERROR, "%s: Generic TLS error", msg);
143 case TLS_BROKEN_PACKET:
144 log(ERROR, "%s: Broken TLS packet", msg);
146 case TLS_NOT_UNDERSTOOD:
147 log(ERROR, "%s: Not understood (TLS)", msg);
150 log(ERROR, "%s: Not safe (TLS)", msg);
152 case TLS_NO_COMMON_CIPHER:
153 log(ERROR, "%s: No common TLS cipher", msg);
155 case TLS_UNEXPECTED_MESSAGE:
156 log(ERROR, "%s: Unexpected TLS message", msg);
158 case TLS_CLOSE_CONNECTION:
159 log(ERROR, "%s: Close TLS connection", msg);
161 case TLS_COMPRESSION_NOT_SUPPORTED:
162 log(ERROR, "%s: TLS compression not supported", msg);
165 log(ERROR, "%s: No TLS memory", msg);
167 case TLS_NOT_VERIFIED:
168 log(ERROR, "%s: Not verified (TLS)", msg);
170 case TLS_INTEGRITY_FAILED:
171 log(ERROR, "%s: TLS integrity failed", msg);
173 case TLS_ERROR_ALERT:
174 log(ERROR, "%s: TLS alert", msg);
176 case TLS_BROKEN_CONNECTION:
177 log(ERROR, "%s: Broken TLS connection", msg);
179 case TLS_BAD_CERTIFICATE:
180 log(ERROR, "%s: Bad TLS certificate", msg);
182 case TLS_UNSUPPORTED_CERTIFICATE:
183 log(ERROR, "%s: Unsupported TLS certificate", msg);
185 case TLS_NO_RENEGOTIATION:
186 log(ERROR, "%s: No TLS renegotiation", msg);
188 case TLS_FEATURE_NOT_SUPPORTED:
189 log(ERROR, "%s: TLS feature not supported", msg);
192 log(ERROR, "%s: Unknown TLS error %d", msg, tls_err);