Browse Source

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 years ago
parent
commit
5e81964e0f
2 changed files with 265 additions and 67 deletions
  1. 53
    6
      include/logger.h
  2. 212
    61
      src/logger.c

+ 53
- 6
include/logger.h View File

@@ -56,11 +56,15 @@
56 56
 #define PYFCGI_LOGGER_FMT_MAX PYFCGI_LOGGER_MAX
57 57
 #define PYFCGI_LOGGER_FIELD_MAX 24
58 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 64
 #define PYFCGI_LOG_LVL_LEN 7
62 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 69
 #define SYSLOG_syslog syslog
66 70
 #define SYSLOG_vsyslog vsyslog
@@ -143,14 +147,21 @@ typedef struct pyfcgi_logger_fmt_field_s pyfcgi_logger_fmt_field_t;
143 147
 typedef union pyfcgi_logger_fmt_field_u pyfcgi_logger_fmt_value_t;
144 148
 typedef enum pyfcgi_logger_field_type pyfcgi_logger_field_type_e;
145 149
 typedef struct strftime_args_s strftime_args_t;
150
+typedef struct ident_args_s ident_args_t;
146 151
 typedef union pyfcgi_logger_field_args pyfcgi_logger_field_args_u;
147 152
 
148 153
 
149 154
 static const short SYSLOG_LVLS[8] = {LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
150 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 166
 static const char* PYFCGI_LOGGER_TYPNAME[] = {"Global", "Access", "Internal",
156 167
                                               "Worker", "Master"};
@@ -188,9 +199,15 @@ struct strftime_args_s
188 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 207
 union pyfcgi_logger_field_args
192 208
 {
193 209
 	strftime_args_t datetime;
210
+	ident_args_t ident;
194 211
 };
195 212
 
196 213
 /**@brief Logger format field's type
@@ -222,6 +239,10 @@ struct pyfcgi_logger_fmt_field_s
222 239
 	pyfcgi_logger_field_args_u args;
223 240
 	/**@brief Points in prefix or sufix buffer */
224 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 248
 /**@brief Logger format data
@@ -236,10 +257,14 @@ struct pyfcgi_logger_format_s
236 257
 	int nfield;
237 258
 	/**@brief Preallocated buffer for prefix & suffix */
238 259
 	char *buf;
260
+	size_t buflen[2];
239 261
 	/**@brief Message prefix */
240 262
 	char *prefix;
241 263
 	/**@brief Message suffix */
242 264
 	char *suffix;
265
+
266
+	char *_msg;
267
+	size_t _msglen;
243 268
 };
244 269
 
245 270
 /**@brief Informations on a logger
@@ -279,7 +304,11 @@ struct pyfcgi_conf_logger_s
279 304
 	//char **format;
280 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 312
 	int pipes[2];
284 313
 };
285 314
 #include "conf.h"
@@ -376,8 +405,26 @@ const char* pyfcgi_logger_value_facility(short);
376 405
  */
377 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 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 428
 int pyfcgi_log(loglvl_t, const char*, ...);
382 429
 int vpyfcgi_log(loglvl_t, const char*, va_list);
383 430
 

+ 212
- 61
src/logger.c View File

@@ -196,7 +196,7 @@ int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
196 196
 {
197 197
 	unsigned short i;
198 198
 	size_t pre_sz, suf_sz;
199
-	char *cur;
199
+	char *cur, pid[PYFCGI_LOG_PID_LEN];
200 200
 	fmt->buf = fmt->prefix = fmt->suffix = NULL;
201 201
 	if(!fmt || !fmt->nfield)
202 202
 	{
@@ -216,6 +216,8 @@ int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
216 216
 	pre_sz = 0;
217 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 221
 		pre_sz+=fmt->fields[i].len;
220 222
 		i++;
221 223
 	}
@@ -223,6 +225,8 @@ int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
223 225
 	suf_sz = 0;
224 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 230
 		suf_sz+=fmt->fields[i].len;
227 231
 		i++;
228 232
 	}
@@ -236,8 +240,16 @@ int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
236 240
 		           strerror(errno));
237 241
 		return PYFCGI_ERR;
238 242
 	}
243
+	memset(fmt->buf, ' ', (pre_sz + suf_sz));
239 244
 	fmt->prefix = pre_sz?fmt->buf:NULL;
240 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 254
 	i=0;
243 255
 	cur = fmt->prefix;
@@ -247,13 +259,25 @@ int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
247 259
 			fmt->fields[i].type != pyfcgi_logger_field_msg)
248 260
 		{
249 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 281
 			cur += fmt->fields[i].len;
258 282
 			i++;
259 283
 		}
@@ -356,7 +380,7 @@ int pyfcgi_logger_parse_field(const char** ptr, const char *start,
356 380
 			cur_field->val = &(PyFCGI_conf.context.pid);
357 381
 			break;
358 382
 		case pyfcgi_logger_field_ident:
359
-			default_len = 0;
383
+			default_len = PyFCGI_conf.logs.ident?strlen(PyFCGI_conf.logs.ident):0;
360 384
 			cur_field->val = &(PyFCGI_conf.logs.ident);
361 385
 			break;
362 386
 		case pyfcgi_logger_field_msg:
@@ -456,8 +480,8 @@ int pyfcgi_logger_parse_field_sz(const char **ptr, size_t *size)
456 480
 const char* pyfcgi_logger_value_level(short lvl)
457 481
 {
458 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 486
 		return NULL;
463 487
 	}
@@ -489,6 +513,144 @@ int pyfcgi_logger_open(pyfcgi_logger_t *logger)
489 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 654
 int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
493 655
 {
494 656
 	int ret;
@@ -503,76 +665,65 @@ int vpyfcgi_log(loglvl_t lvl, const char *fmt, va_list ap)
503 665
 {
504 666
 	int len, ret;
505 667
 	pyfcgi_conf_logger_t *conf;
668
+	pyfcgi_logger_t *logger;
506 669
 	unsigned char i;
507
-	char buf[512];
670
+	size_t msglen, real_len;
671
+	void *tmp;
508 672
 	va_list o_ap;
509 673
 
674
+
510 675
 	conf = &PyFCGI_conf.logs;
511 676
 
512 677
 	va_copy(o_ap, ap);
513 678
 	_vsyslog(lvl, fmt, o_ap);
514 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 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 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 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…
Cancel
Save