18 // Yes, it's a bit ugly.
19 #define SYSLOG_FAKE_FILE (static_cast<FILE *>(nullptr))
21 bool logging_started = false;
22 vector<FILE *> log_destinations;
24 void add_log_destination_file(const string &filename)
26 FILE *fp = fopen(filename.c_str(), "a");
28 perror(filename.c_str());
32 log_destinations.push_back(fp);
35 void add_log_destination_console()
37 log_destinations.push_back(stderr);
40 void add_log_destination_syslog()
42 openlog("cubemap", LOG_PID, LOG_DAEMON);
43 log_destinations.push_back(SYSLOG_FAKE_FILE);
48 logging_started = true;
51 void shut_down_logging()
53 for (size_t i = 0; i < log_destinations.size(); ++i) {
54 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
56 } else if (log_destinations[i] != stderr) {
57 if (fclose(log_destinations[i]) != 0) {
62 log_destinations.clear();
63 logging_started = false;
66 void log(LogLevel log_level, const char *fmt, ...)
68 char formatted_msg[4096];
71 vsnprintf(formatted_msg, sizeof(formatted_msg), fmt, ap);
74 time_t now = time(nullptr);
76 struct tm *ltime = localtime_r(&now, <);
78 if (ltime == nullptr) {
79 strcpy(timestamp, "???");
81 strftime(timestamp, sizeof(timestamp), "%a, %d %b %Y %T %z", ltime);
84 const char *log_level_str;
89 log_level_str = "INFO: ";
90 syslog_level = LOG_INFO;
93 log_level_str = "WARNING: ";
94 syslog_level = LOG_WARNING;
97 log_level_str = "ERROR: ";
98 syslog_level = LOG_ERR;
104 // Log to stderr if logging hasn't been set up yet. Note that this means
105 // that such messages will come even if there are no “error_log” lines.
106 if (!logging_started) {
107 fprintf(stderr, "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
111 for (size_t i = 0; i < log_destinations.size(); ++i) {
112 if (log_destinations[i] == SYSLOG_FAKE_FILE) {
113 syslog(syslog_level, "%s", formatted_msg);
115 int err = fprintf(log_destinations[i], "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
119 if (log_destinations[i] != stderr) {
120 fflush(log_destinations[i]);
126 void log_perror(const char *msg)
129 log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
132 void log_tls_error(const char *msg, int tls_err)
135 case TLS_NEED_MORE_DATA:
136 log(ERROR, "%s: Need more data (TLS)", msg);
138 case TLS_GENERIC_ERROR:
139 log(ERROR, "%s: Generic TLS error", msg);
141 case TLS_BROKEN_PACKET:
142 log(ERROR, "%s: Broken TLS packet", msg);
144 case TLS_NOT_UNDERSTOOD:
145 log(ERROR, "%s: Not understood (TLS)", msg);
148 log(ERROR, "%s: Not safe (TLS)", msg);
150 case TLS_NO_COMMON_CIPHER:
151 log(ERROR, "%s: No common TLS cipher", msg);
153 case TLS_UNEXPECTED_MESSAGE:
154 log(ERROR, "%s: Unexpected TLS message", msg);
156 case TLS_CLOSE_CONNECTION:
157 log(ERROR, "%s: Close TLS connection", msg);
159 case TLS_COMPRESSION_NOT_SUPPORTED:
160 log(ERROR, "%s: TLS compression not supported", msg);
163 log(ERROR, "%s: No TLS memory", msg);
165 case TLS_NOT_VERIFIED:
166 log(ERROR, "%s: Not verified (TLS)", msg);
168 case TLS_INTEGRITY_FAILED:
169 log(ERROR, "%s: TLS integrity failed", msg);
171 case TLS_ERROR_ALERT:
172 log(ERROR, "%s: TLS alert", msg);
174 case TLS_BROKEN_CONNECTION:
175 log(ERROR, "%s: Broken TLS connection", msg);
177 case TLS_BAD_CERTIFICATE:
178 log(ERROR, "%s: Bad TLS certificate", msg);
180 case TLS_UNSUPPORTED_CERTIFICATE:
181 log(ERROR, "%s: Unsupported TLS certificate", msg);
183 case TLS_NO_RENEGOTIATION:
184 log(ERROR, "%s: No TLS renegotiation", msg);
186 case TLS_FEATURE_NOT_SUPPORTED:
187 log(ERROR, "%s: TLS feature not supported", msg);
190 log(ERROR, "%s: Unknown TLS error %d", msg, tls_err);