log.c 9.7 KB
Newer Older
1 2 3 4 5 6
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
7
#include <stdint.h>
K
Kozlov Dmitry 已提交
8
#include <signal.h>
9 10
#include <sys/time.h>

11 12 13 14
#include "triton/mempool.h"
#include "events.h"
#include "ppp.h"

15 16
#include "log.h"

D
Dmitry Kozlov 已提交
17 18
#include "memdebug.h"

K
Kozlov Dmitry 已提交
19 20 21 22 23 24 25
#define LOG_MSG   0
#define LOG_ERROR 1
#define LOG_WARN  2
#define LOG_INFO1 3
#define LOG_INFO2 4
#define LOG_DEBUG 5

26 27 28 29 30 31
struct log_pd_t
{
	struct ppp_pd_t pd;
	struct ppp_t *ppp;
	struct list_head msgs;
	struct log_msg_t *msg;
D
Dmitry Kozlov 已提交
32
	int authorized:1;
33
};
34

35 36 37 38 39 40
struct _log_msg_t
{
	struct list_head entry;
	int level;
	struct timeval timestamp;
	struct list_head chunks;
D
Dmitry Kozlov 已提交
41
	unsigned int refs;
42
};
43

K
Kozlov Dmitry 已提交
44
static int log_level;
45

46 47 48 49 50 51 52
static LIST_HEAD(targets);
static mempool_t msg_pool;
static mempool_t _msg_pool;
static mempool_t chunk_pool;

static __thread struct ppp_t *cur_ppp;
static __thread struct _log_msg_t *cur_msg;
53
static __thread char *stat_buf;
D
Dmitry Kozlov 已提交
54
static pthread_key_t stat_buf_key;
55 56

static FILE *emerg_file;
D
Dmitry Kozlov 已提交
57
static FILE *debug_file;
58 59 60 61

static void _log_free_msg(struct _log_msg_t *msg);
static struct log_msg_t *clone_msg(struct _log_msg_t *msg);
static int add_msg(struct _log_msg_t *msg, const char *buf);
62
//static struct log_pd_t *find_pd(struct ppp_t *ppp);
D
Dmitry Kozlov 已提交
63
static void write_msg(FILE *f, struct _log_msg_t *msg, struct ppp_t *ppp);
64

D
Dmitry Kozlov 已提交
65 66 67 68 69
static void stat_buf_free(void *ptr)
{
	_free(ptr);
}

70
static void do_log(int level, const char *fmt, va_list ap, struct ppp_t *ppp)
71
{
72 73 74
	struct log_target_t *t;
	struct log_msg_t *m;

D
Dmitry Kozlov 已提交
75
	if (!stat_buf) {
76
		stat_buf = _malloc(LOG_MAX_SIZE + 1);
D
Dmitry Kozlov 已提交
77 78
		pthread_setspecific(stat_buf_key, stat_buf);
	}
79

80
	vsnprintf(stat_buf, LOG_MAX_SIZE, fmt, ap);
D
Dmitry Kozlov 已提交
81

82 83 84 85 86 87 88 89
	if (!cur_msg) {
		cur_msg = mempool_alloc(_msg_pool);
		if (!cur_msg)
			return;
		INIT_LIST_HEAD(&cur_msg->chunks);
		cur_msg->refs = 1;
		cur_msg->level = level;
		gettimeofday(&cur_msg->timestamp, NULL);
90
	}
91

92 93 94 95 96 97
	if (add_msg(cur_msg, stat_buf))
		goto out;

	if (stat_buf[strlen(stat_buf) - 1] != '\n')
		return;

D
Dmitry Kozlov 已提交
98 99 100
	if (debug_file)
		write_msg(debug_file, cur_msg, ppp);

101
	list_for_each_entry(t, &targets, entry) {
102 103 104
		m = clone_msg(cur_msg);
		if (!m)
			break;
105
		t->log(t, m, ppp);
106 107 108
	}

out:
109
	_log_free_msg(cur_msg);
110
	cur_msg = NULL;
111
}
112

K
Kozlov Dmitry 已提交
113
void __export log_error(const char *fmt,...)
114
{
115
	if (log_level >= LOG_ERROR) {
116 117
		va_list ap;
		va_start(ap,fmt);
118 119
		do_log(LOG_ERROR, fmt, ap, NULL);
		va_end(ap);
120 121
	}
}
122

K
Kozlov Dmitry 已提交
123
void __export log_warn(const char *fmt,...)
124
{
125
	if (log_level >= LOG_WARN) {
126 127
		va_list ap;
		va_start(ap,fmt);
128 129
		do_log(LOG_WARN, fmt, ap, NULL);
		va_end(ap);
130 131
	}
}
132

133
void __export log_info1(const char *fmt,...)
134
{
135
	if (log_level >= LOG_INFO1) {
136
		va_list ap;
137
		va_start(ap, fmt);
138 139 140 141 142 143 144 145 146 147 148
		do_log(LOG_INFO1, fmt, ap, NULL);
		va_end(ap);
	}
}

void __export log_info2(const char *fmt,...)
{
	if (log_level >= LOG_INFO2) {
		va_list ap;
		va_start(ap, fmt);
		do_log(LOG_INFO2, fmt, ap, NULL);
149
		va_end(ap);
150 151
	}
}
152

K
Kozlov Dmitry 已提交
153
void __export log_debug(const char *fmt,...)
154
{
155
	if (log_level >= LOG_DEBUG) {
156
		va_list ap;
157 158 159
		va_start(ap, fmt);
		do_log(LOG_DEBUG, fmt, ap, NULL);
		va_end(ap);
160 161 162
	}
}

163 164 165 166 167 168 169 170
void __export log_debug2(const char *fmt,...)
{
	va_list ap;
	va_start(ap, fmt);
	vfprintf(debug_file, fmt, ap);
	va_end(ap);
	fflush(debug_file);
}
K
Kozlov Dmitry 已提交
171
void __export log_msg(const char *fmt,...)
172 173
{
	va_list ap;
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	va_start(ap, fmt);
	do_log(LOG_MSG, fmt, ap, NULL);
	va_end(ap);
}

void __export log_ppp_error(const char *fmt,...)
{
	if (log_level >= LOG_ERROR) {
		va_list ap;
		va_start(ap, fmt);
		do_log(LOG_ERROR, fmt, ap, cur_ppp);
		va_end(ap);
	}
}

void __export log_ppp_warn(const char *fmt,...)
{
	if (log_level >= LOG_WARN) {
		va_list ap;
		va_start(ap, fmt);
		do_log(LOG_WARN, fmt, ap, cur_ppp);
		va_end(ap);
	}
}

199 200 201 202 203 204 205 206 207 208 209
void __export log_ppp_info1(const char *fmt,...)
{
	if (log_level >= LOG_INFO1) {
		va_list ap;
		va_start(ap, fmt);
		do_log(LOG_INFO1, fmt, ap, cur_ppp);
		va_end(ap);
	}
}

void __export log_ppp_info2(const char *fmt,...)
210
{
211
	if (log_level >= LOG_INFO2) {
212 213
		va_list ap;
		va_start(ap, fmt);
214
		do_log(LOG_INFO2, fmt, ap, cur_ppp);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
		va_end(ap);
	}
}

void __export log_ppp_debug(const char *fmt,...)
{
	if (log_level >= LOG_DEBUG) {
		va_list ap;
		va_start(ap, fmt);
		do_log(LOG_DEBUG, fmt, ap, cur_ppp);
		va_end(ap);
	}
}

void __export log_ppp_msg(const char *fmt,...)
{
	va_list ap;
	va_start(ap, fmt);
	do_log(LOG_MSG, fmt, ap, cur_ppp);
	va_end(ap);
}

void __export log_emerg(const char *fmt, ...)
{
	if (emerg_file) {
		va_list ap;
		va_start(ap, fmt);
		vfprintf(emerg_file, fmt, ap);
		va_end(ap);
244
		fflush(emerg_file);
245 246 247 248 249 250 251
	}
}

void __export log_free_msg(struct log_msg_t *m)
{
	struct _log_msg_t *msg = (struct _log_msg_t *)m->lpd;

252 253
	//printf("free msg %p\n", m);
	
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
	mempool_free(m->hdr);
	_log_free_msg(msg);

	mempool_free(m);
}


static void _log_free_msg(struct _log_msg_t *msg)
{
	struct log_chunk_t *chunk;

	if (__sync_sub_and_fetch(&msg->refs, 1))
		return;
	
	while(!list_empty(&msg->chunks)) {
		chunk = list_entry(msg->chunks.next, typeof(*chunk), entry);
		list_del(&chunk->entry);
		mempool_free(chunk);
	}

	mempool_free(msg);
275 276
}

277
static struct log_msg_t *clone_msg(struct _log_msg_t *msg)
278
{
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
	struct log_msg_t *m = mempool_alloc(msg_pool);
	if (!m) {
		log_emerg("log: out of memory\n");
		return NULL;
	}
	
	m->hdr = mempool_alloc(chunk_pool);
	if (!m->hdr) {
		log_emerg("log: out of memory\n");
		mempool_free(m);
		return NULL;
	}	

	m->hdr->len = 0;
	m->lpd = msg;
	m->chunks = &msg->chunks;
	m->timestamp = msg->timestamp;
	m->level = msg->level;

298
	__sync_add_and_fetch(&msg->refs, 1);
299

300
	//printf("clone msg %p\n", m);
301
	return m;
302
}
K
Kozlov Dmitry 已提交
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
static int add_msg(struct _log_msg_t *msg, const char *buf)
{
	struct log_chunk_t *chunk;
	int i, len, chunk_cnt;
	
	len = strlen(buf);
	chunk_cnt = (len - 1)/LOG_CHUNK_SIZE + 1;

	for (i = 0; i < chunk_cnt; i++) {
		chunk = mempool_alloc(chunk_pool);
		if (!chunk)
			return -1;

		chunk->len = i == chunk_cnt -1 ? len - i * LOG_CHUNK_SIZE : LOG_CHUNK_SIZE;
		memcpy(chunk->msg, buf + i * LOG_CHUNK_SIZE, chunk->len);
		chunk->msg[chunk->len] = 0;

		list_add_tail(&chunk->entry, &msg->chunks);
	}

	return 0;
}

D
Dmitry Kozlov 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
static void write_msg(FILE *f, struct _log_msg_t *msg, struct ppp_t *ppp)
{
	struct log_chunk_t *chunk;

	if (ppp)
		sprintf(stat_buf,"%s: %s: ", ppp->ifname, ppp->sessionid);
	else
		stat_buf[0] = 0;
	
	list_for_each_entry(chunk, &msg->chunks, entry)
		strcat(stat_buf, chunk->msg);
	
	fwrite(stat_buf, strlen(stat_buf), 1, f);
	fflush(f);
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
/*static struct log_pd_t *find_pd(struct ppp_t *ppp)
{
	struct ppp_pd_t *pd;
	struct log_pd_t *lpd;

	list_for_each_entry(pd, &ppp->pd_list, entry) {
		if (pd->key == &pd_key) {
			lpd = container_of(pd, typeof(*lpd), pd);
			return lpd;
		}
	}
	log_emerg("log:BUG: pd not found\n");
	abort();
}

358 359
static void ev_ctrl_starting(struct ppp_t *ppp)
{
D
Dmitry Kozlov 已提交
360
	struct log_pd_t *lpd = _malloc(sizeof(*lpd));
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	if (!lpd) {
		log_emerg("log: out of memory\n");
		return;
	}

	memset(lpd, 0, sizeof(*lpd));
	lpd->pd.key = &pd_key;
	lpd->ppp = ppp;
	INIT_LIST_HEAD(&lpd->msgs);
	list_add_tail(&lpd->pd.entry, &ppp->pd_list);
}

static void ev_ctrl_finished(struct ppp_t *ppp)
{
	struct log_pd_t *lpd = find_pd(ppp);
	struct _log_msg_t *msg;
	struct log_msg_t *m;
	struct log_target_t *t;

	if (lpd->msg) {
		log_emerg("log:BUG: lpd->msg is not NULL\n");
		abort();
	}

D
Dmitry Kozlov 已提交
385
	if (lpd->authorized) {
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
		if (!list_empty(&lpd->msgs)) {
			log_emerg("log:BUG: lpd->msgs is not empty\n");
			abort();
		}
		list_for_each_entry(t, &targets, entry)
			if (t->session_stop)
				t->session_stop(ppp);
	}

	while (!list_empty(&lpd->msgs)) {
		msg = list_entry(lpd->msgs.next, typeof(*msg), entry);
		list_del(&msg->entry);

		list_for_each_entry(t, &targets, entry) {
			if (!t->log)
				continue;
			m = clone_msg(msg);
			if (!m)
				break;
			t->log(m);
		}

		_log_free_msg(msg);
	}

	list_del(&lpd->pd.entry);
D
Dmitry Kozlov 已提交
412
	_free(lpd);
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
}

static void ev_ppp_authorized(struct ppp_t *ppp)
{
	struct log_pd_t *lpd = find_pd(ppp);
	struct _log_msg_t *msg;
	struct log_msg_t *m;
	struct log_target_t *t;
	
	list_for_each_entry(t, &targets, entry)
		if (t->session_start)
			t->session_start(ppp);

	while(!list_empty(&lpd->msgs)) {
		msg = list_entry(lpd->msgs.next, typeof(*msg), entry);
		list_del(&msg->entry);

		list_for_each_entry(t, &targets, entry) {
			if (!t->session_log)
				continue;
			m = clone_msg(msg);
			if (!m)
				break;
			t->session_log(lpd->ppp, m);
		}

		_log_free_msg(msg);
	}
D
Dmitry Kozlov 已提交
441 442

	lpd->authorized = 1;
443
}*/
444 445 446 447 448 449

void __export log_switch(struct triton_context_t *ctx, void *arg)
{
	cur_ppp = (struct ppp_t *)arg;
}

K
Kozlov Dmitry 已提交
450

451 452 453 454 455
void __export log_register_target(struct log_target_t *t)
{
	list_add_tail(&t->entry, &targets);
}

K
Kozlov Dmitry 已提交
456 457 458 459 460 461 462 463 464
static void sighup(int n)
{
	struct log_target_t *t;

	list_for_each_entry(t, &targets, entry)
		if (t->reopen)
			t->reopen();
}

465
static void load_config(void)
466 467
{
	char *opt;
K
Kozlov Dmitry 已提交
468

K
Kozlov Dmitry 已提交
469 470 471 472
	opt = conf_get_opt("log", "level");
	if (opt && atoi(opt) >= 0)
		log_level = atoi(opt);

473 474
	opt = conf_get_opt("log", "log-emerg");
	if (opt) {
475 476 477 478
		if (emerg_file)
			emerg_file = freopen(opt, "a", emerg_file);
		else
			emerg_file = fopen(opt, "a");
479 480
		if (!emerg_file)
			fprintf(stderr, "log:open: %s\n", strerror(errno));
481 482 483
	} else if (emerg_file) {
		fclose(emerg_file);
		emerg_file = NULL;
484 485
	}

D
Dmitry Kozlov 已提交
486 487
	opt = conf_get_opt("log", "log-debug");
	if (opt) {
488 489 490 491 492
		if (debug_file)
			debug_file = freopen(opt, "a", debug_file);
		else
			debug_file = fopen(opt, "a");
		if (!debug_file)
D
Dmitry Kozlov 已提交
493
			fprintf(stderr, "log:open: %s\n", strerror(errno));
494 495 496
	} else if (debug_file) {
		fclose(debug_file);
		debug_file = NULL;
D
Dmitry Kozlov 已提交
497
	}
498 499
}

500
static void log_init(void)
501 502 503 504
{
	struct sigaction sa = {
		.sa_handler = sighup,
	};
D
Dmitry Kozlov 已提交
505

D
Dmitry Kozlov 已提交
506 507
	pthread_key_create(&stat_buf_key, stat_buf_free);

508 509 510
	msg_pool = mempool_create(sizeof(struct log_msg_t));
	_msg_pool = mempool_create(sizeof(struct _log_msg_t));
	chunk_pool = mempool_create(sizeof(struct log_chunk_t) + LOG_CHUNK_SIZE + 1);
K
Kozlov Dmitry 已提交
511

512
	load_config();
K
Kozlov Dmitry 已提交
513

514 515 516
	triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);

	sigaction(SIGHUP, &sa, NULL);
517
}
K
Kozlov Dmitry 已提交
518

519
DEFINE_INIT(0, log_init);