Переглянути джерело

Updated log function, add a format_message function, debuging etc.

Implement the set_ident function (wich update the internal preffix & suffix
representations)
Yann Weber 4 роки тому
джерело
коміт
5e81964e0f
2 змінених файлів з 265 додано та 67 видалено
  1. 53
    6
      include/logger.h
  2. 212
    61
      src/logger.c

+ 53
- 6
include/logger.h Переглянути файл

56
 #define PYFCGI_LOGGER_FMT_MAX PYFCGI_LOGGER_MAX
56
 #define PYFCGI_LOGGER_FMT_MAX PYFCGI_LOGGER_MAX
57
 #define PYFCGI_LOGGER_FIELD_MAX 24
57
 #define PYFCGI_LOGGER_FIELD_MAX 24
58
 #define PYFCGI_LOGGER_FMT_PARSE_ERRSZ 64
58
 #define PYFCGI_LOGGER_FMT_PARSE_ERRSZ 64
59
+/**@brief The size of the @ref struct pyfcgi_logger_format_t.buf allocated to
60
+ * the message field */
61
+#define PYFCGI_LOGGER_MSG_BUF_SZ 64
59
 
62
 
60
-#define PYFCGI_LOG_DTM_LEN 10
63
+#define PYFCGI_LOG_DTM_LEN 25
61
 #define PYFCGI_LOG_LVL_LEN 7
64
 #define PYFCGI_LOG_LVL_LEN 7
62
 #define PYFCGI_LOG_TYP_LEN 7
65
 #define PYFCGI_LOG_TYP_LEN 7
63
-#define PYFCGI_LOG_PID_LEN 5
66
+#define PYFCGI_LOG_PID_LEN 4
67
+#define PYFCGI_LOG_PID_FMT "%04d"
64
 
68
 
65
 #define SYSLOG_syslog syslog
69
 #define SYSLOG_syslog syslog
66
 #define SYSLOG_vsyslog vsyslog
70
 #define SYSLOG_vsyslog vsyslog
143
 typedef union pyfcgi_logger_fmt_field_u pyfcgi_logger_fmt_value_t;
147
 typedef union pyfcgi_logger_fmt_field_u pyfcgi_logger_fmt_value_t;
144
 typedef enum pyfcgi_logger_field_type pyfcgi_logger_field_type_e;
148
 typedef enum pyfcgi_logger_field_type pyfcgi_logger_field_type_e;
145
 typedef struct strftime_args_s strftime_args_t;
149
 typedef struct strftime_args_s strftime_args_t;
150
+typedef struct ident_args_s ident_args_t;
146
 typedef union pyfcgi_logger_field_args pyfcgi_logger_field_args_u;
151
 typedef union pyfcgi_logger_field_args pyfcgi_logger_field_args_u;
147
 
152
 
148
 
153
 
149
 static const short SYSLOG_LVLS[8] = {LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
154
 static const short SYSLOG_LVLS[8] = {LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
150
                                      LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG};
155
                                      LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG};
151
-static const char* PYFCGI_LOGGER_LVLNAME[] = {"Emergency", "Alert", "Critical",
152
-                                              "Error", "Warning", "Notice",
153
-					      "Info", "Debug"};
156
+static const char* PYFCGI_LOGGER_LVLNAME[] = {
157
+	" Emerge",
158
+	"  Alert",
159
+	" Critic",
160
+	"  Error",
161
+	"Warning",
162
+	" Notice",
163
+	"   Info",
164
+	"  Debug"};
154
 
165
 
155
 static const char* PYFCGI_LOGGER_TYPNAME[] = {"Global", "Access", "Internal",
166
 static const char* PYFCGI_LOGGER_TYPNAME[] = {"Global", "Access", "Internal",
156
                                               "Worker", "Master"};
167
                                               "Worker", "Master"};
188
 	//const struct tm *tm; // fecthed each time
199
 	//const struct tm *tm; // fecthed each time
189
 };
200
 };
190
 
201
 
202
+struct ident_args_s
203
+{
204
+	size_t len;
205
+};
206
+
191
 union pyfcgi_logger_field_args
207
 union pyfcgi_logger_field_args
192
 {
208
 {
193
 	strftime_args_t datetime;
209
 	strftime_args_t datetime;
210
+	ident_args_t ident;
194
 };
211
 };
195
 
212
 
196
 /**@brief Logger format field's type
213
 /**@brief Logger format field's type
222
 	pyfcgi_logger_field_args_u args;
239
 	pyfcgi_logger_field_args_u args;
223
 	/**@brief Points in prefix or sufix buffer */
240
 	/**@brief Points in prefix or sufix buffer */
224
 	char *buf_ptr;
241
 	char *buf_ptr;
242
+	/**@brief Field offset in msg buffer (prefix or sufix) */
243
+	size_t buf_off;
244
+	/**@brief 1 if in suffix else 0 */
245
+	short suff;
225
 };
246
 };
226
 
247
 
227
 /**@brief Logger format data
248
 /**@brief Logger format data
236
 	int nfield;
257
 	int nfield;
237
 	/**@brief Preallocated buffer for prefix & suffix */
258
 	/**@brief Preallocated buffer for prefix & suffix */
238
 	char *buf;
259
 	char *buf;
260
+	size_t buflen[2];
239
 	/**@brief Message prefix */
261
 	/**@brief Message prefix */
240
 	char *prefix;
262
 	char *prefix;
241
 	/**@brief Message suffix */
263
 	/**@brief Message suffix */
242
 	char *suffix;
264
 	char *suffix;
265
+
266
+	char *_msg;
267
+	size_t _msglen;
243
 };
268
 };
244
 
269
 
245
 /**@brief Informations on a logger
270
 /**@brief Informations on a logger
279
 	//char **format;
304
 	//char **format;
280
 	unsigned char format_sz;
305
 	unsigned char format_sz;
281
 
306
 
282
-	/**@brief Internal pipe to tee(2) the message on loggers */
307
+	/**@brief Buffer for message field formating */
308
+	char *msg_buf;
309
+	size_t msg_buf_sz;
310
+
311
+	/**@brief Internal pipe to tee(2) the message on loggers (USELESS)*/
283
 	int pipes[2];
312
 	int pipes[2];
284
 };
313
 };
285
 #include "conf.h"
314
 #include "conf.h"
376
  */
405
  */
377
 int pyfcgi_logger_open(pyfcgi_logger_t*);
406
 int pyfcgi_logger_open(pyfcgi_logger_t*);
378
 
407
 
408
+/**@brief Set programm identity for logger
409
+ * @note ident is global to a process
410
+ * @note this function triggers the refresh of the loggers internal
411
+ * buffers if needed (see @ref pyfcgi_logger_format_bufinit() )
412
+ * @param const char* new_ident
413
+ * @return 0 if no error
414
+ */
379
 int pyfcgi_logger_set_ident(const char*);
415
 int pyfcgi_logger_set_ident(const char*);
380
 
416
 
417
+/**@brief Format a message using a @ref struct pyfcgi_logger_format_s
418
+ * @note alloc and write the logline in the attribute _msg
419
+ * @param pyfcgi_logger_format_t the pyfcgi logger format structure
420
+ * @param loglvl_t the loglevel (see @ref pyfcgi_log() )
421
+ * @param char* message the message sent by user
422
+ * @param size_t len the message len
423
+ * @return NULL if error
424
+ */
425
+char* vpyfcgi_logger_format_message(pyfcgi_logger_format_t *fmt,
426
+	loglvl_t lvl, const char* message, size_t len);
427
+
381
 int pyfcgi_log(loglvl_t, const char*, ...);
428
 int pyfcgi_log(loglvl_t, const char*, ...);
382
 int vpyfcgi_log(loglvl_t, const char*, va_list);
429
 int vpyfcgi_log(loglvl_t, const char*, va_list);
383
 
430
 

+ 212
- 61
src/logger.c Переглянути файл

196
 {
196
 {
197
 	unsigned short i;
197
 	unsigned short i;
198
 	size_t pre_sz, suf_sz;
198
 	size_t pre_sz, suf_sz;
199
-	char *cur;
199
+	char *cur, pid[PYFCGI_LOG_PID_LEN];
200
 	fmt->buf = fmt->prefix = fmt->suffix = NULL;
200
 	fmt->buf = fmt->prefix = fmt->suffix = NULL;
201
 	if(!fmt || !fmt->nfield)
201
 	if(!fmt || !fmt->nfield)
202
 	{
202
 	{
216
 	pre_sz = 0;
216
 	pre_sz = 0;
217
 	while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
217
 	while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
218
 	{
218
 	{
219
+		fmt->fields[i].buf_off = pre_sz;
220
+		fmt->fields[i].suff = 0;
219
 		pre_sz+=fmt->fields[i].len;
221
 		pre_sz+=fmt->fields[i].len;
220
 		i++;
222
 		i++;
221
 	}
223
 	}
223
 	suf_sz = 0;
225
 	suf_sz = 0;
224
 	while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
226
 	while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
225
 	{
227
 	{
228
+		fmt->fields[i].buf_off = suf_sz;
229
+		fmt->fields[i].suff = 1;
226
 		suf_sz+=fmt->fields[i].len;
230
 		suf_sz+=fmt->fields[i].len;
227
 		i++;
231
 		i++;
228
 	}
232
 	}
236
 		           strerror(errno));
240
 		           strerror(errno));
237
 		return PYFCGI_ERR;
241
 		return PYFCGI_ERR;
238
 	}
242
 	}
243
+	memset(fmt->buf, ' ', (pre_sz + suf_sz));
239
 	fmt->prefix = pre_sz?fmt->buf:NULL;
244
 	fmt->prefix = pre_sz?fmt->buf:NULL;
240
 	fmt->suffix = suf_sz?(fmt->buf + pre_sz):NULL;
245
 	fmt->suffix = suf_sz?(fmt->buf + pre_sz):NULL;
246
+	fmt->prefix[pre_sz-1] = '\0';
247
+	if(fmt->suffix)
248
+	{
249
+		fmt->suffix[suf_sz-1] = '\0';
250
+	}
251
+	fmt->buflen[0] = pre_sz - 1;//not counting '\0'
252
+	fmt->buflen[1] = suf_sz;
241
 
253
 
242
 	i=0;
254
 	i=0;
243
 	cur = fmt->prefix;
255
 	cur = fmt->prefix;
247
 			fmt->fields[i].type != pyfcgi_logger_field_msg)
259
 			fmt->fields[i].type != pyfcgi_logger_field_msg)
248
 		{
260
 		{
249
 			fmt->fields[i].buf_ptr = cur;
261
 			fmt->fields[i].buf_ptr = cur;
250
-			if(fmt->fields[i].len && (
251
-				fmt->fields[i].type == pyfcgi_logger_field_const ||
252
-				fmt->fields[i].type == pyfcgi_logger_field_ident))
253
-			{// copy const fields
254
-				strncpy(cur, fmt->fields[i].val,
255
-					fmt->fields[i].len);
262
+			memset(cur, ' ', fmt->fields[i].len);
263
+			switch(fmt->fields[i].type)
264
+			{
265
+				
266
+				case pyfcgi_logger_field_const:
267
+				case pyfcgi_logger_field_ident:
268
+					memcpy(cur, fmt->fields[i].val,
269
+						fmt->fields[i].len);
270
+					break;
271
+				case pyfcgi_logger_field_pid:
272
+					snprintf(pid, PYFCGI_LOG_PID_LEN+1,
273
+						PYFCGI_LOG_PID_FMT,
274
+						*((pid_t*)fmt->fields[i].val));
275
+					memcpy(cur, pid, PYFCGI_LOG_PID_LEN);
276
+					break;
277
+				default:
278
+					break;
256
 			}
279
 			}
280
+//dprintf(2, "field %d type %d off %ld len %ld '%s' p'%s' s'%s'\n", i, fmt->fields[i].type, fmt->fields[i].buf_off, fmt->fields[i].len, cur, fmt->prefix, fmt->suffix);
257
 			cur += fmt->fields[i].len;
281
 			cur += fmt->fields[i].len;
258
 			i++;
282
 			i++;
259
 		}
283
 		}
356
 			cur_field->val = &(PyFCGI_conf.context.pid);
380
 			cur_field->val = &(PyFCGI_conf.context.pid);
357
 			break;
381
 			break;
358
 		case pyfcgi_logger_field_ident:
382
 		case pyfcgi_logger_field_ident:
359
-			default_len = 0;
383
+			default_len = PyFCGI_conf.logs.ident?strlen(PyFCGI_conf.logs.ident):0;
360
 			cur_field->val = &(PyFCGI_conf.logs.ident);
384
 			cur_field->val = &(PyFCGI_conf.logs.ident);
361
 			break;
385
 			break;
362
 		case pyfcgi_logger_field_msg:
386
 		case pyfcgi_logger_field_msg:
456
 const char* pyfcgi_logger_value_level(short lvl)
480
 const char* pyfcgi_logger_value_level(short lvl)
457
 {
481
 {
458
 	short idx;
482
 	short idx;
459
-	idx = (lvl & 0xF0) >> 4;
460
-	if(idx < 0 || idx >= sizeof(PYFCGI_LOGGER_LVLNAME))
483
+	idx = ((lvl & 0xF0) >> 4)-1;
484
+	if(idx < 0 || idx > 7)
461
 	{
485
 	{
462
 		return NULL;
486
 		return NULL;
463
 	}
487
 	}
489
 	return 0;
513
 	return 0;
490
 }
514
 }
491
 
515
 
516
+int pyfcgi_logger_set_ident(const char* new_ident)
517
+{
518
+	pyfcgi_conf_logger_t *conf;
519
+	pyfcgi_logger_format_t *fmt;
520
+	pyfcgi_logger_fmt_field_t *field;
521
+	size_t i, j, len;
522
+	short upd;
523
+
524
+	conf = &PyFCGI_conf.logs;
525
+	if( !(conf->ident = strdup(new_ident)) )
526
+	{
527
+		pyfcgi_log(LOG_ALERT,
528
+			"Error duplicating identity for logger : %s",
529
+			strerror(errno));
530
+		return PYFCGI_FATAL;
531
+	}
532
+	len = strlen(new_ident);
533
+	for(i=0; i<conf->format_sz; i++)
534
+	{
535
+		fmt = &(conf->formats[i]);
536
+		upd = 0;
537
+		for(j=0; j<fmt->nfield; j++)
538
+		{
539
+			field = &(fmt->fields[j]);
540
+			if(field->type == pyfcgi_logger_field_ident)
541
+			{
542
+				field->len = len;
543
+				upd = 0;
544
+			}
545
+		}
546
+		if(upd)
547
+		{
548
+			pyfcgi_logger_format_bufinit(fmt);
549
+		}
550
+	}
551
+	return 0;
552
+}
553
+
554
+char* vpyfcgi_logger_format_message(pyfcgi_logger_format_t *fmt,
555
+	loglvl_t lvl, const char* message, size_t fmt_msg_len)
556
+{
557
+	char *_msgptr;
558
+	size_t maxlen;
559
+	int ret;
560
+	void *tmp;
561
+	size_t i, suff_off;
562
+	pyfcgi_logger_fmt_field_t *field;
563
+	struct tm *curtime;
564
+	time_t _curtime;
565
+	size_t (*_strftime)(char*, size_t, const char*, const struct tm*);
566
+
567
+
568
+	if(!fmt->_msg)
569
+	{ //first message, allocating message buffer
570
+		fmt->_msglen = fmt->buflen[0] + fmt->buflen[1] + fmt_msg_len;
571
+		// rounding upper
572
+		fmt->_msglen >>= 6;
573
+		fmt->_msglen++;
574
+		fmt->_msglen <<= 6;
575
+		fmt->_msg = malloc(sizeof(char) * fmt->_msglen);
576
+		if(!fmt->_msg)
577
+		{
578
+			//TODO : error
579
+dprintf(2, "ERROR ALLOC _msg : %s", strerror(errno));
580
+			return NULL;
581
+		}
582
+		memset(fmt->_msg, ' ', sizeof(char)*fmt->_msglen);
583
+		fmt->_msg[fmt->_msglen - 1] = '\0';
584
+		memcpy(fmt->_msg, fmt->prefix, fmt->buflen[0]);
585
+	}
586
+	while(1)
587
+	{
588
+		maxlen = fmt->_msglen - (fmt->buflen[0] + fmt->buflen[1]);
589
+		if(fmt_msg_len < maxlen)
590
+		{
591
+			// TODO check errors
592
+			break;
593
+		}
594
+		fmt->_msglen = fmt_msg_len + fmt->buflen[0] + fmt->buflen[1];
595
+		fmt->_msglen >>= 6;
596
+		fmt->_msglen++;
597
+		fmt->_msglen <<= 6;
598
+		tmp = realloc(fmt->_msg, sizeof(char) * fmt->_msglen);
599
+		if(!tmp)
600
+		{
601
+			//TODO : error
602
+dprintf(2, "ERROR REALLOC _msg : %s", strerror(errno));
603
+			return NULL;
604
+		}
605
+	}
606
+	memcpy(fmt->_msg + fmt->buflen[0], message, fmt_msg_len);
607
+	suff_off = fmt->buflen[0] + fmt_msg_len;
608
+	if(fmt->buflen[1])
609
+	{
610
+		strncpy(fmt->_msg + suff_off, fmt->suffix,
611
+			fmt->buflen[1]);
612
+		//TODO check errors
613
+	}
614
+	else
615
+	{
616
+		fmt->_msg[suff_off] = '\0';
617
+	}
618
+	// update fmt->_msg dynamic fields
619
+	time(&_curtime);
620
+	curtime = localtime(&_curtime);
621
+	for(i=0; i<fmt->nfield; i++)
622
+	{
623
+		field = &(fmt->fields[i]);
624
+		_msgptr = fmt->_msg;
625
+		_msgptr += fmt->fields->suff?suff_off:0;
626
+		_msgptr += field->buf_off;
627
+		switch(field->type)
628
+		{
629
+			case pyfcgi_logger_field_datetime:
630
+				_strftime = field->val?field->val:strftime;
631
+				ret = _strftime(_msgptr, field->len,
632
+					field->args.datetime.format,
633
+					curtime);
634
+				if(!ret)
635
+				{
636
+					//TODO ERROR
637
+dprintf(2,"Not enough space to write datetime in '%s', need more than %ld\n",
638
+	fmt->fmt, field->len);
639
+				}
640
+				_msgptr[ret] = ' ';
641
+				break;
642
+			case pyfcgi_logger_field_level:
643
+				memcpy(_msgptr,
644
+					pyfcgi_logger_value_level(lvl),
645
+					field->len);
646
+				break;
647
+			default:
648
+				break;
649
+		}
650
+	}
651
+	return fmt->_msg;
652
+}
653
+
492
 int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
654
 int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
493
 {
655
 {
494
 	int ret;
656
 	int ret;
503
 {
665
 {
504
 	int len, ret;
666
 	int len, ret;
505
 	pyfcgi_conf_logger_t *conf;
667
 	pyfcgi_conf_logger_t *conf;
668
+	pyfcgi_logger_t *logger;
506
 	unsigned char i;
669
 	unsigned char i;
507
-	char buf[512];
670
+	size_t msglen, real_len;
671
+	void *tmp;
508
 	va_list o_ap;
672
 	va_list o_ap;
509
 
673
 
674
+
510
 	conf = &PyFCGI_conf.logs;
675
 	conf = &PyFCGI_conf.logs;
511
 
676
 
512
 	va_copy(o_ap, ap);
677
 	va_copy(o_ap, ap);
513
 	_vsyslog(lvl, fmt, o_ap);
678
 	_vsyslog(lvl, fmt, o_ap);
514
 	va_end(o_ap);
679
 	va_end(o_ap);
515
 
680
 
516
-	len = 0;
517
-	if(conf->format_sz > 1)
518
-	{
519
-		len = vdprintf(conf->pipes[1], fmt, ap);
520
-		if(len < 0)
681
+	ret = 0;
682
+	// processing message before sending it to formats
683
+	while(1)
684
+	{
685
+		va_copy(o_ap, ap);
686
+		msglen = vsnprintf(conf->msg_buf, conf->msg_buf_sz, fmt, o_ap);
687
+		real_len = msglen;
688
+		va_end(o_ap);
689
+		// Rounding msglen
690
+		msglen >>=6;
691
+		msglen++;
692
+		msglen <<=6;
693
+		if(msglen <= conf->msg_buf_sz)
521
 		{
694
 		{
522
-			_syslog(LOG_ALERT, 
523
-			       "Unable to write to multiplexer pipe when trying to log : %s",
524
-			       strerror(errno));
525
-			return PYFCGI_FATAL;
695
+			break;
526
 		}
696
 		}
527
-	}
528
-	else if (conf->format_sz)
529
-	{
530
-		len = vdprintf(conf->loggers[0].fd, fmt, ap);
531
-		if(len < 0)
697
+		conf->msg_buf_sz = msglen;
698
+		tmp = realloc(conf->msg_buf,
699
+			sizeof(char)*conf->msg_buf_sz);
700
+		if(!tmp)
532
 		{
701
 		{
533
-			_syslog(LOG_ALERT, 
534
-			       "Unable to write to single FD to '%s' when trying to log : %s",
535
-			       conf->loggers[0].filename, strerror(errno));
702
+			// TODO : error
703
+dprintf(2, "ERROR REALLOC conf_msg : %s", strerror(errno));
704
+			if(conf->msg_buf) { free(conf->msg_buf); }
536
 			return PYFCGI_FATAL;
705
 			return PYFCGI_FATAL;
537
 		}
706
 		}
538
-		return 0;
707
+		conf->msg_buf = tmp;
708
+	}
709
+
710
+	// populating format messages
711
+	for(i=0; i<conf->format_sz; i++)
712
+	{
713
+		vpyfcgi_logger_format_message(&(conf->formats[i]), lvl,
714
+			conf->msg_buf, real_len);
539
 	}
715
 	}
540
-	for(i=0; i<conf->logger_sz-1; i++)
716
+	for(i=0; i<conf->logger_sz; i++)
541
 	{
717
 	{
542
-		ret = tee(conf->pipes[0], conf->loggers[i].fd, len, 0);
543
-		if(ret < 0)
718
+		logger = &(conf->loggers[i]);
719
+		len = dprintf(logger->fd, conf->formats[logger->fmt_id]._msg);
720
+		if(len < 0)
544
 		{
721
 		{
545
 			_syslog(LOG_ALERT, 
722
 			_syslog(LOG_ALERT, 
546
-			       "Unable to splice to last logfile '%s' : %s",
723
+			       "Unable to write to single FD to '%s' when trying to log : %s",
547
 			       conf->loggers[i].filename, strerror(errno));
724
 			       conf->loggers[i].filename, strerror(errno));
548
-			return PYFCGI_FATAL;
725
+			ret = PYFCGI_FATAL;
549
 		}
726
 		}
550
 	}
727
 	}
551
-	ret = splice(conf->pipes[0], NULL, conf->loggers[i].fd, NULL, len, 0);
552
-	if(ret < 0)
553
-	{
554
-		_syslog(LOG_ALERT, 
555
-		       "Unable to splice to last logfile '%s' : %s",
556
-		       conf->loggers[i].filename, strerror(errno));
557
-		return PYFCGI_ERR;
558
-	}
559
-	if(ret < len)
560
-	{
561
-		_syslog(LOG_WARNING, 
562
-		       "Unable to splice all data to logfile. Flushing pipe.");
563
-
564
-		do
565
-		{
566
-			len -= (ret<len)?ret:len;
567
-			ret = read(conf->pipes[0], buf, (len>sizeof(buf))?sizeof(buf):len);
568
-			if(ret < 0)
569
-			{
570
-				_syslog(LOG_CRIT,
571
-				        "Logger pipe seems broken, unable to flush : %s",
572
-					strerror(errno));
573
-				return PYFCGI_ERR;
574
-			}
575
-		}while(len);
576
-	}
577
-	return 0;
728
+	return ret;
578
 }
729
 }

Loading…
Відмінити
Зберегти