File: log.cpp

package info (click to toggle)
cubemap 1.5.2-3
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 908 kB
  • sloc: ansic: 8,411; cpp: 5,730; sh: 114; perl: 112; makefile: 76
file content (195 lines) | stat: -rw-r--r-- 4,444 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <string>
#include <vector>

#include "tlse.h"

#include "log.h"

using namespace std;

// Yes, it's a bit ugly.
#define SYSLOG_FAKE_FILE (static_cast<FILE *>(nullptr))

bool logging_started = false;
vector<FILE *> log_destinations;

void add_log_destination_file(const string &filename)
{
	FILE *fp = fopen(filename.c_str(), "ae");
	if (fp == nullptr) {
		perror(filename.c_str());
		return;
	}

	log_destinations.push_back(fp);	
}

void add_log_destination_console()
{
	log_destinations.push_back(stderr);
}

void add_log_destination_syslog()
{
	openlog("cubemap", LOG_PID, LOG_DAEMON);
	log_destinations.push_back(SYSLOG_FAKE_FILE);
}

void start_logging()
{
	logging_started = true;
}

void shut_down_logging()
{
	for (size_t i = 0; i < log_destinations.size(); ++i) {
		if (log_destinations[i] == SYSLOG_FAKE_FILE) {
			closelog();
		} else if (log_destinations[i] != stderr) {
			if (fclose(log_destinations[i]) != 0) {
				perror("fclose");
			}
		}
	}
	log_destinations.clear();
	logging_started = false;
}

void log(LogLevel log_level, const char *fmt, ...)
{
	char formatted_msg[4096];
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(formatted_msg, sizeof(formatted_msg), fmt, ap);
	va_end(ap);

	time_t now = time(nullptr);
	struct tm lt;
	struct tm *ltime = localtime_r(&now, &lt);
	char timestamp[1024];
	if (ltime == nullptr) {
		strcpy(timestamp, "???");
	} else {
		strftime(timestamp, sizeof(timestamp), "%a, %d %b %Y %T %z", ltime);
	}

	const char *log_level_str;
	int syslog_level;

	switch (log_level) {
	case INFO:
		log_level_str = "INFO:    ";
		syslog_level = LOG_INFO;
		break;
	case WARNING:
		log_level_str = "WARNING: ";
		syslog_level = LOG_WARNING;
		break;
	case ERROR:
		log_level_str = "ERROR:   ";
		syslog_level = LOG_ERR;
		break;
	default:
		assert(false);
	}

	// Log to stderr if logging hasn't been set up yet. Note that this means
	// that such messages will come even if there are no “error_log” lines.
	if (!logging_started) {
		fprintf(stderr, "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
		return;
	}

	for (size_t i = 0; i < log_destinations.size(); ++i) {
                if (log_destinations[i] == SYSLOG_FAKE_FILE) {
			syslog(syslog_level, "%s", formatted_msg);
		} else {
			int err = fprintf(log_destinations[i], "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
			if (err < 0) {
				perror("fprintf");
			}
			if (log_destinations[i] != stderr) {
				fflush(log_destinations[i]);
			}
		}
	}
}

void log_perror(const char *msg)
{
	char errbuf[4096];
	log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
}

void log_tls_error(const char *msg, int tls_err)
{
	switch (tls_err) {
	case TLS_NEED_MORE_DATA:
		log(ERROR, "%s: Need more data (TLS)", msg);
		break;
	case TLS_GENERIC_ERROR:
		log(ERROR, "%s: Generic TLS error", msg);
		break;
	case TLS_BROKEN_PACKET:
		log(ERROR, "%s: Broken TLS packet", msg);
		break;
	case TLS_NOT_UNDERSTOOD:
		log(ERROR, "%s: Not understood (TLS)", msg);
		break;
	case TLS_NOT_SAFE:
		log(ERROR, "%s: Not safe (TLS)", msg);
		break;
	case TLS_NO_COMMON_CIPHER:
		log(ERROR, "%s: No common TLS cipher", msg);
		break;
	case TLS_UNEXPECTED_MESSAGE:
		log(ERROR, "%s: Unexpected TLS message", msg);
		break;
	case TLS_CLOSE_CONNECTION:
		log(ERROR, "%s: Close TLS connection", msg);
		break;
	case TLS_COMPRESSION_NOT_SUPPORTED:
		log(ERROR, "%s: TLS compression not supported", msg);
		break;
	case TLS_NO_MEMORY:
		log(ERROR, "%s: No TLS memory", msg);
		break;
	case TLS_NOT_VERIFIED:
		log(ERROR, "%s: Not verified (TLS)", msg);
		break;
	case TLS_INTEGRITY_FAILED:
		log(ERROR, "%s: TLS integrity failed", msg);
		break;
	case TLS_ERROR_ALERT:
		log(ERROR, "%s: TLS alert", msg);
		break;
	case TLS_BROKEN_CONNECTION:
		log(ERROR, "%s: Broken TLS connection", msg);
		break;
	case TLS_BAD_CERTIFICATE:
		log(ERROR, "%s: Bad TLS certificate", msg);
		break;
	case TLS_UNSUPPORTED_CERTIFICATE:
		log(ERROR, "%s: Unsupported TLS certificate", msg);
		break;
	case TLS_NO_RENEGOTIATION:
		log(ERROR, "%s: No TLS renegotiation", msg);
		break;
	case TLS_FEATURE_NOT_SUPPORTED:
		log(ERROR, "%s: TLS feature not supported", msg);
		break;
	default:
		log(ERROR, "%s: Unknown TLS error %d", msg, tls_err);
		break;
	}
}