Tests about a simple python3 fastcgi runner using libfcgi and the Python-C API.
python
c
wsgi
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logger.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. #include "logger.h"
  2. int pyfcgi_logger_init()
  3. {
  4. pyfcgi_conf_logger_t *conf;
  5. conf = &PyFCGI_conf.logs;
  6. memset(conf, 0, sizeof(pyfcgi_conf_logger_t));
  7. return 0;
  8. }
  9. int pyfcgi_logger_stop()
  10. {
  11. pyfcgi_conf_logger_t *conf;
  12. pyfcgi_logger_format_t *fmt;
  13. size_t i, j;
  14. conf = &PyFCGI_conf.logs;
  15. for(i=0; i<conf->logger_sz; i++)
  16. {
  17. _pyfcgi_logger_free(&(conf->loggers[i]));
  18. }
  19. for(i=0; i<conf->format_sz; i++)
  20. {
  21. fmt = &(conf->formats[i]);
  22. for(j=0; j<fmt->nfield; j++)
  23. {
  24. pyfcgi_logger_field_free(&(fmt->fields[j]));
  25. }
  26. free(conf->formats[i].buf);
  27. }
  28. return 0;
  29. }
  30. void pyfcgi_logger_enable_syslog(const char* nident)
  31. {
  32. pyfcgi_conf_logger_t *conf;
  33. char ident[64];
  34. size_t ret;
  35. conf = &PyFCGI_conf.logs;
  36. if(conf->flags & PYFCGI_LOG_FSYSLOG)
  37. {
  38. closelog();
  39. }
  40. conf->flags |= PYFCGI_LOG_FSYSLOG;
  41. ret = 0;
  42. if(nident)
  43. {
  44. ret = snprintf(ident, 64, PYFCGI_SYSLOG_IDENT_FMT,
  45. getpid(), nident);
  46. }
  47. if(!nident || ret >= 64)
  48. {
  49. ret = snprintf(ident, 64, PYFCGI_SYSLOG_IDENT_FMT_SHORT,
  50. getpid());
  51. if(ret <= 64)
  52. {
  53. snprintf(ident, 64, "pyfcgi");
  54. }
  55. }
  56. if(conf->syslog_ident)
  57. {
  58. free(conf->syslog_ident);
  59. }
  60. conf->syslog_ident = strdup(ident);
  61. openlog(conf->syslog_ident, LOG_CONS | LOG_PERROR, LOG_DAEMON | LOG_USER);
  62. }
  63. void _pyfcgi_logger_free(pyfcgi_logger_t *logger)
  64. {
  65. free(logger->filename);
  66. }
  67. int pyfcgi_logger_add(const char *filename, logmask_t loglvl, logmask_t logtyp,
  68. const char *format)
  69. {
  70. pyfcgi_conf_logger_t *conf;
  71. pyfcgi_logger_t logger;
  72. size_t new_idx;
  73. int err;
  74. conf = &PyFCGI_conf.logs;
  75. if(conf->logger_sz >= PYFCGI_LOGGER_MAX)
  76. {
  77. pyfcgi_log(LOG_ERR, "Maximum of 255 logger reached, unable to add this one...");
  78. return PYFCGI_ERR;
  79. }
  80. if(pyfcgi_logger_format_add(format, &(logger.fmt_id)))
  81. {
  82. return PYFCGI_FATAL;
  83. }
  84. logger.loglvl = loglvl;
  85. logger.logtyp = logtyp;
  86. if(!filename)
  87. {
  88. logger.filename = NULL;
  89. }
  90. else
  91. {
  92. logger.filename = strdup(filename);
  93. if(!logger.filename)
  94. {
  95. err = errno;
  96. pyfcgi_log(LOG_ALERT,
  97. "Unable to duplicate logger filename : %s",
  98. strerror(err));
  99. return PYFCGI_FATAL;
  100. }
  101. }
  102. new_idx = conf->logger_sz;
  103. conf->logger_sz++;
  104. conf->loggers[new_idx] = logger;
  105. pyfcgi_logger_open(&(conf->loggers[new_idx]));
  106. return 0;
  107. }
  108. int pyfcgi_logger_format_add(const char* format, size_t* idx)
  109. {
  110. size_t i;
  111. pyfcgi_conf_logger_t *conf;
  112. int ret;
  113. conf = &PyFCGI_conf.logs;
  114. if(!format)
  115. {
  116. format = PYFCGI_LOGGER_FMT_DEFAULT;
  117. }
  118. for(i=0; i<conf->format_sz; i++)
  119. {
  120. if(!strcmp(format, conf->formats[i].fmt)) { break; }
  121. }
  122. if(idx) { *idx = i; }
  123. if( i<conf->format_sz )
  124. {
  125. return 0;
  126. }
  127. conf->format_sz++;
  128. if( !(ret = pyfcgi_logger_parse_format(format, &(conf->formats[i]))) )
  129. { // No error, allocating format buffer
  130. pyfcgi_logger_format_bufinit(&(conf->formats[i]));
  131. }
  132. return ret;
  133. }
  134. int pyfcgi_logger_parse_format(const char* fmt,
  135. pyfcgi_logger_format_t* fmt_data)
  136. {
  137. const char *ptr, *str_start;
  138. int err;
  139. char reason_err[PYFCGI_LOGGER_FMT_PARSE_ERRSZ];
  140. pyfcgi_logger_fmt_field_t *cur_field;
  141. memset(fmt_data, 0, sizeof(pyfcgi_logger_format_t));
  142. if( !(fmt_data->fmt = strdup(fmt)) )
  143. {
  144. pyfcgi_log(LOG_ALERT, "Fails to strdup new format : %s",
  145. strerror(errno));
  146. return PYFCGI_FATAL;
  147. }
  148. ptr = fmt;
  149. fmt_data->nfield = 0;
  150. cur_field = fmt_data->fields;
  151. while(*ptr)
  152. {
  153. if(fmt_data->nfield >= PYFCGI_LOGGER_FIELD_MAX)
  154. {
  155. //TODO error truncate !
  156. //break;
  157. goto parse_err;
  158. }
  159. str_start = ptr;
  160. cur_field->len = 0;
  161. while(*ptr && (*ptr != '{' || *(ptr+1) == '{'))
  162. { // handling const chr fields
  163. //TODO : issue warning/error when unescaped '}' found
  164. if(*ptr == '{' && *(ptr+1) == '{')
  165. {
  166. cur_field->len++;
  167. ptr++;
  168. }
  169. cur_field->len++;
  170. ptr++;
  171. }
  172. if(cur_field->len)
  173. {
  174. cur_field->known_length = 1;
  175. cur_field->type = pyfcgi_logger_field_const;
  176. cur_field->val = strndup(str_start, cur_field->len);
  177. if(!cur_field->val)
  178. {
  179. err = errno;
  180. pyfcgi_log(LOG_ALERT,
  181. "Unable to strdup part of format : %s",
  182. strerror(err));
  183. goto exit_err;
  184. }
  185. fmt_data->nfield++;
  186. cur_field = &(fmt_data->fields[fmt_data->nfield]); // next_field
  187. continue; // to check fmt_data->nfield
  188. }
  189. if(*ptr == '{') //should be this or '\0'...
  190. {
  191. ptr++;
  192. if( pyfcgi_logger_parse_field(&ptr, fmt, cur_field,
  193. reason_err) )
  194. {
  195. goto parse_err;
  196. }
  197. fmt_data->nfield++;
  198. cur_field = &(fmt_data->fields[fmt_data->nfield]); // next_field
  199. }
  200. ptr++;
  201. };
  202. return 0;
  203. parse_err:
  204. pyfcgi_log(LOG_ERR, "Logger format parse error at chr %ld : %s",
  205. ptr - fmt, reason_err);
  206. exit_err:
  207. //TODO free const str from fields
  208. memset(fmt_data, 0, sizeof(pyfcgi_logger_format_t));
  209. return PYFCGI_ERR;
  210. }
  211. int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t* fmt)
  212. {
  213. volatile unsigned short i;
  214. size_t pre_sz, suf_sz;
  215. char *cur, pid[PYFCGI_LOG_PID_LEN];
  216. fmt->buf = fmt->prefix = fmt->suffix = NULL;
  217. if(!fmt || !fmt->nfield)
  218. {
  219. return 1;
  220. }
  221. if(fmt->nfield == 1 && fmt->fields[0].type == pyfcgi_logger_field_msg)
  222. {
  223. // no other field than message, buf, prefix & suffix are NULL
  224. return 0;
  225. }
  226. if(fmt->buf)
  227. { // if it is not the first call
  228. free(fmt->buf);
  229. }
  230. if(fmt->_msg)
  231. { // delete message buffer to force prefix copy
  232. free(fmt->_msg);
  233. fmt->_msg = NULL;
  234. }
  235. i = 0;
  236. pre_sz = 0;
  237. while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
  238. {
  239. fmt->fields[i].buf_off = pre_sz;
  240. fmt->fields[i].suff = 0;
  241. pre_sz+=fmt->fields[i].len;
  242. i++;
  243. }
  244. i++;
  245. suf_sz = 0;
  246. while(i<fmt->nfield && fmt->fields[i].type != pyfcgi_logger_field_msg)
  247. {
  248. fmt->fields[i].buf_off = suf_sz;
  249. fmt->fields[i].suff = 1;
  250. suf_sz+=fmt->fields[i].len;
  251. i++;
  252. }
  253. pre_sz += pre_sz?1:0;
  254. suf_sz += suf_sz?1:0;
  255. fmt->buf = malloc(sizeof(char) * (pre_sz + suf_sz));
  256. if(!fmt->buf)
  257. {
  258. fmt->buf = fmt->prefix = fmt->suffix = NULL;
  259. pyfcgi_log(LOG_ALERT, "Unable to allocate logger buffer : %s",
  260. strerror(errno));
  261. return PYFCGI_ERR;
  262. }
  263. memset(fmt->buf, ' ', (pre_sz + suf_sz));
  264. fmt->prefix = pre_sz?fmt->buf:NULL;
  265. fmt->suffix = suf_sz?(fmt->buf + pre_sz):NULL;
  266. fmt->prefix[pre_sz-1] = '\0';
  267. if(fmt->suffix)
  268. {
  269. fmt->suffix[suf_sz-1] = '\0';
  270. }
  271. fmt->buflen[0] = pre_sz - 1;//not counting '\0'
  272. fmt->buflen[1] = suf_sz;
  273. i=0;
  274. cur = fmt->prefix;
  275. while(i<fmt->nfield)
  276. {
  277. while(i<fmt->nfield &&
  278. fmt->fields[i].type != pyfcgi_logger_field_msg)
  279. {
  280. fmt->fields[i].buf_ptr = cur;
  281. memset(cur, ' ', fmt->fields[i].len);
  282. switch(fmt->fields[i].type)
  283. {
  284. case pyfcgi_logger_field_const:
  285. memcpy(cur, fmt->fields[i].val,
  286. fmt->fields[i].len);
  287. break;
  288. case pyfcgi_logger_field_ident:
  289. memcpy(cur, PyFCGI_conf.logs.ident,
  290. fmt->fields[i].len);
  291. break;
  292. case pyfcgi_logger_field_pid:
  293. snprintf(pid, PYFCGI_LOG_PID_LEN+1,
  294. PYFCGI_LOG_PID_FMT,
  295. *((pid_t*)fmt->fields[i].val));
  296. memcpy(cur, pid, PYFCGI_LOG_PID_LEN);
  297. break;
  298. default:
  299. break;
  300. }
  301. //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);
  302. cur += fmt->fields[i].len;
  303. i++;
  304. }
  305. if(fmt->fields[i].type == pyfcgi_logger_field_msg)
  306. {
  307. cur = fmt->suffix;
  308. i++;
  309. }
  310. }
  311. return 0;
  312. }
  313. int pyfcgi_logger_parse_field(const char** ptr, const char *start,
  314. pyfcgi_logger_fmt_field_t* cur_field,
  315. char fail_reason[PYFCGI_LOGGER_FMT_PARSE_ERRSZ])
  316. {
  317. const char *str_start, *field_start;
  318. int ret;
  319. char **name, *cname, **format;
  320. size_t default_len;
  321. pyfcgi_logger_field_type_e *type;
  322. char *field_names[] = {"datetime", "level", "facility", "pid", "ident",
  323. "msg", NULL};
  324. pyfcgi_logger_field_type_e field_types[] = {
  325. pyfcgi_logger_field_datetime, pyfcgi_logger_field_level,
  326. pyfcgi_logger_field_facility, pyfcgi_logger_field_pid,
  327. pyfcgi_logger_field_ident, pyfcgi_logger_field_msg};
  328. str_start = *ptr;
  329. field_start = *ptr;
  330. name = field_names;
  331. type = field_types;
  332. while(*name)
  333. {
  334. cname = *name;
  335. if(*cname != **ptr)
  336. {
  337. name++;
  338. type++;
  339. continue;
  340. }
  341. // Name found ?
  342. while(**ptr && *cname && **ptr != ':' && **ptr != '}' &&
  343. **ptr == *cname)
  344. {
  345. (*ptr)++;
  346. cname++;
  347. }
  348. if(**ptr == ':' || **ptr == '}')
  349. {
  350. cur_field->type = *type;
  351. break;
  352. }
  353. else
  354. {
  355. *name = field_names[6]; // NULL
  356. break;
  357. }
  358. }
  359. if(!name)
  360. {
  361. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  362. "unknown field type '%s' chr %ld",
  363. str_start, str_start - start);
  364. return 1;
  365. }
  366. if(**ptr == ':') { (*ptr)++; } // next option
  367. if(pyfcgi_logger_parse_field_sz(ptr, &(cur_field->len)))
  368. {
  369. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  370. "Unable to parse field size chr %ld '%s'",
  371. str_start - start, str_start);
  372. return 1;
  373. }
  374. if(**ptr == ':') { (*ptr)++; } // next option
  375. str_start = *ptr;
  376. cur_field->known_length = 1;
  377. switch(cur_field->type)
  378. {
  379. case pyfcgi_logger_field_datetime:
  380. default_len = PYFCGI_LOG_DTM_LEN;
  381. cur_field->val = (void*)strftime;
  382. format = &(cur_field->args.datetime.format);
  383. ret = pyfcgi_logger_parse_field_dtfmt(ptr,format);
  384. if(ret){
  385. return ret;
  386. }
  387. break;
  388. case pyfcgi_logger_field_level:
  389. default_len = PYFCGI_LOG_LVL_LEN;
  390. cur_field->val = (void*)pyfcgi_logger_value_level;
  391. break;
  392. case pyfcgi_logger_field_facility:
  393. default_len = PYFCGI_LOG_TYP_LEN;
  394. cur_field->val = (void*)pyfcgi_logger_value_facility;
  395. break;
  396. case pyfcgi_logger_field_pid:
  397. default_len = PYFCGI_LOG_PID_LEN;
  398. cur_field->val = &(PyFCGI_conf.context.pid);
  399. break;
  400. case pyfcgi_logger_field_ident:
  401. default_len = PyFCGI_conf.logs.ident?strlen(PyFCGI_conf.logs.ident):0;
  402. cur_field->val = &(PyFCGI_conf.logs.ident);
  403. break;
  404. case pyfcgi_logger_field_msg:
  405. cur_field->known_length = 0;
  406. default_len = 0;
  407. break;
  408. default:
  409. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  410. "Unknown error parsing field '%s' at chr %ld",
  411. field_start , *ptr - start);
  412. return 1;
  413. }
  414. if(!cur_field->len && default_len)
  415. {
  416. cur_field->len = default_len;
  417. }
  418. return 0;
  419. }
  420. void pyfcgi_logger_field_free(pyfcgi_logger_fmt_field_t* field)
  421. {
  422. switch(field->type)
  423. {
  424. case pyfcgi_logger_field_const:
  425. if(field->val)
  426. {
  427. free(field->val);
  428. }
  429. break;
  430. case pyfcgi_logger_field_datetime:
  431. if(field->args.datetime.format)
  432. {
  433. free(field->args.datetime.format);
  434. }
  435. break;
  436. case pyfcgi_logger_field_null:
  437. case pyfcgi_logger_field_level:
  438. case pyfcgi_logger_field_facility:
  439. case pyfcgi_logger_field_pid:
  440. case pyfcgi_logger_field_ppid:
  441. case pyfcgi_logger_field_ident:
  442. case pyfcgi_logger_field_msg:
  443. break;
  444. }
  445. }
  446. int pyfcgi_logger_parse_field_dtfmt(const char** ptr, char** format)
  447. {
  448. const char *fmt;
  449. size_t fmt_len;
  450. fmt_len = 0;
  451. fmt = *ptr;
  452. while(**ptr && **ptr != '}' && *((*ptr)+1) != '}')
  453. {
  454. (*ptr)++;
  455. fmt_len++;
  456. }
  457. if(!(**ptr))
  458. {
  459. //TODO error
  460. }
  461. if(!fmt_len)
  462. {
  463. fmt_len = sizeof(PYFCGI_LOGGER_TIME_FMT_DEFAULT);
  464. fmt = PYFCGI_LOGGER_TIME_FMT_DEFAULT;
  465. }
  466. if(!(*format = strndup(fmt, fmt_len+1)))
  467. {
  468. pyfcgi_log(LOG_ALERT,
  469. "Unable to strdup field datetime format : %s",
  470. strerror(errno));
  471. return PYFCGI_FATAL;
  472. }
  473. return 0;
  474. }
  475. int pyfcgi_logger_parse_field_sz(const char **ptr, size_t *size)
  476. {
  477. char *end;
  478. *size = 0;
  479. if(**ptr == '}' || **ptr == ':')
  480. {
  481. return 0;
  482. }
  483. if(**ptr < '0' || **ptr > '9')
  484. {
  485. return 1; // parse error
  486. }
  487. *size = strtoull(*ptr, &end, 10);
  488. *ptr = end;
  489. return 0;
  490. }
  491. const char* pyfcgi_logger_value_level(short lvl)
  492. {
  493. short idx;
  494. idx = ((lvl & 0xF0) >> 4)-1;
  495. if(idx < 0 || idx > 7)
  496. {
  497. return NULL;
  498. }
  499. return PYFCGI_LOGGER_LVLNAME[idx];
  500. }
  501. const char* pyfcgi_logger_value_facility(short typ)
  502. {
  503. short idx;
  504. idx = typ & 0x0F;
  505. if(idx < 0 || idx >= sizeof(PYFCGI_LOGGER_TYPNAME))
  506. {
  507. return NULL;
  508. }
  509. return PYFCGI_LOGGER_TYPNAME[idx];
  510. }
  511. int pyfcgi_logger_open(pyfcgi_logger_t *logger)
  512. {
  513. if(!logger->filename)
  514. {
  515. logger->fd = 2;
  516. return 0;
  517. }
  518. if( ((logger->fd = open(logger->filename,
  519. O_WRONLY | O_APPEND | O_CREAT, 00640)) < 0) )
  520. {
  521. pyfcgi_log(LOG_ERR,
  522. "Unable to open log file '%s' : %s",
  523. strerror(errno));
  524. return PYFCGI_ERR;
  525. }
  526. return 0;
  527. }
  528. int pyfcgi_logger_set_ident(const char* new_ident)
  529. {
  530. pyfcgi_conf_logger_t *conf;
  531. pyfcgi_logger_format_t *fmt;
  532. pyfcgi_logger_fmt_field_t *field;
  533. size_t i, j, len;
  534. short upd;
  535. conf = &PyFCGI_conf.logs;
  536. if(conf->ident)
  537. {
  538. free(conf->ident);
  539. }
  540. if( !(conf->ident = strdup(new_ident)) )
  541. {
  542. pyfcgi_log(LOG_ALERT,
  543. "Error duplicating identity for logger : %s",
  544. strerror(errno));
  545. return PYFCGI_FATAL;
  546. }
  547. if(conf->flags & PYFCGI_LOG_FSYSLOG)
  548. {
  549. pyfcgi_logger_enable_syslog(new_ident);
  550. }
  551. len = strlen(conf->ident);
  552. for(i=0; i<conf->format_sz; i++)
  553. {
  554. fmt = &(conf->formats[i]);
  555. upd = 0;
  556. for(j=0; j<fmt->nfield; j++)
  557. {
  558. field = &(fmt->fields[j]);
  559. if(field->type == pyfcgi_logger_field_ident)
  560. {
  561. field->len = len;
  562. upd = 1;
  563. }
  564. }
  565. if(upd)
  566. {
  567. pyfcgi_logger_format_bufinit(fmt);
  568. }
  569. }
  570. return 0;
  571. }
  572. char* vpyfcgi_logger_format_message(pyfcgi_logger_format_t *fmt,
  573. loglvl_t lvl, const char* message, size_t fmt_msg_len)
  574. {
  575. /**@todo Add '\n' when suffix is used ! */
  576. char *_msgptr;
  577. size_t maxlen;
  578. int ret;
  579. void *tmp;
  580. size_t i, suff_off;
  581. pyfcgi_logger_fmt_field_t *field;
  582. struct tm *curtime;
  583. time_t _curtime;
  584. size_t (*_strftime)(char*, size_t, const char*, const struct tm*);
  585. if(!fmt->_msg)
  586. { //first message, allocating message buffer
  587. fmt->_msglen = fmt->buflen[0] + fmt->buflen[1] + fmt_msg_len + 1;
  588. // rounding upper
  589. fmt->_msglen >>= 6;
  590. fmt->_msglen++;
  591. fmt->_msglen <<= 6;
  592. fmt->_msg = malloc(sizeof(char) * fmt->_msglen);
  593. if(!fmt->_msg)
  594. {
  595. //TODO : error
  596. dprintf(2, "ERROR ALLOC _msg : %s\n", strerror(errno));
  597. return NULL;
  598. }
  599. memset(fmt->_msg, ' ', sizeof(char)*fmt->_msglen);
  600. fmt->_msg[fmt->_msglen - 1] = '\0';
  601. memcpy(fmt->_msg, fmt->prefix, fmt->buflen[0]);
  602. }
  603. while(1)
  604. {
  605. maxlen = fmt->_msglen - (fmt->buflen[0] + fmt->buflen[1]);
  606. if(fmt_msg_len < maxlen)
  607. {
  608. // TODO check errors
  609. break;
  610. }
  611. fmt->_msglen = fmt_msg_len + fmt->buflen[0] + fmt->buflen[1] + 1;
  612. fmt->_msglen >>= 6;
  613. fmt->_msglen++;
  614. fmt->_msglen <<= 6;
  615. tmp = realloc(fmt->_msg, sizeof(char) * fmt->_msglen);
  616. if(!tmp)
  617. {
  618. //TODO : error
  619. dprintf(2, "ERROR REALLOC _msg : %s", strerror(errno));
  620. return NULL;
  621. }
  622. fmt->_msg = tmp;
  623. }
  624. memcpy(fmt->_msg + fmt->buflen[0], message, fmt_msg_len);
  625. suff_off = fmt->buflen[0] + fmt_msg_len;
  626. if(fmt->buflen[1])
  627. {
  628. strncpy(fmt->_msg + suff_off, fmt->suffix,
  629. fmt->buflen[1]);
  630. //TODO check errors
  631. fmt->_msg[suff_off+fmt->buflen[1]] = '\n';
  632. fmt->_msg[suff_off+fmt->buflen[1]+1] = '\0';
  633. }
  634. else
  635. {
  636. fmt->_msg[suff_off] = '\n';
  637. fmt->_msg[suff_off+1] = '\0';
  638. }
  639. // update fmt->_msg dynamic fields
  640. time(&_curtime);
  641. curtime = localtime(&_curtime);
  642. for(i=0; i<fmt->nfield; i++)
  643. {
  644. field = &(fmt->fields[i]);
  645. _msgptr = fmt->_msg;
  646. _msgptr += fmt->fields->suff?suff_off:0;
  647. _msgptr += field->buf_off;
  648. switch(field->type)
  649. {
  650. case pyfcgi_logger_field_datetime:
  651. _strftime = field->val?field->val:strftime;
  652. ret = _strftime(_msgptr, field->len,
  653. field->args.datetime.format,
  654. curtime);
  655. if(!ret)
  656. {
  657. //TODO ERROR
  658. dprintf(2,"Not enough space to write datetime in '%s', need more than %ld\n",
  659. fmt->fmt, field->len);
  660. }
  661. _msgptr[ret] = ' ';
  662. break;
  663. case pyfcgi_logger_field_level:
  664. memcpy(_msgptr,
  665. pyfcgi_logger_value_level(lvl),
  666. field->len);
  667. break;
  668. default:
  669. break;
  670. }
  671. }
  672. return fmt->_msg;
  673. }
  674. int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
  675. {
  676. int ret;
  677. va_list ap;
  678. va_start(ap, fmt);
  679. ret = vpyfcgi_log(lvl, fmt, ap);
  680. va_end(ap);
  681. return ret;
  682. }
  683. int vpyfcgi_log(loglvl_t lvl, const char *fmt, va_list ap)
  684. {
  685. int len, ret;
  686. pyfcgi_conf_logger_t *conf;
  687. pyfcgi_logger_t *logger;
  688. unsigned char i;
  689. size_t msglen, real_len;
  690. void *tmp;
  691. va_list o_ap;
  692. conf = &PyFCGI_conf.logs;
  693. va_copy(o_ap, ap);
  694. _vsyslog(lvl, fmt, o_ap);
  695. va_end(o_ap);
  696. ret = 0;
  697. // processing message before sending it to formats
  698. while(1)
  699. {
  700. va_copy(o_ap, ap);
  701. msglen = vsnprintf(conf->msg_buf, conf->msg_buf_sz, fmt, o_ap);
  702. real_len = msglen;
  703. va_end(o_ap);
  704. // Rounding msglen
  705. msglen >>=6;
  706. msglen++;
  707. msglen <<=6;
  708. if(msglen <= conf->msg_buf_sz)
  709. {
  710. break;
  711. }
  712. conf->msg_buf_sz = msglen;
  713. tmp = realloc(conf->msg_buf,
  714. sizeof(char)*conf->msg_buf_sz);
  715. if(!tmp)
  716. {
  717. // TODO : error
  718. dprintf(2, "ERROR REALLOC conf_msg : %s", strerror(errno));
  719. if(conf->msg_buf) { free(conf->msg_buf); }
  720. return PYFCGI_FATAL;
  721. }
  722. conf->msg_buf = tmp;
  723. }
  724. // populating format messages
  725. for(i=0; i<conf->format_sz; i++)
  726. {
  727. vpyfcgi_logger_format_message(&(conf->formats[i]), lvl,
  728. conf->msg_buf, real_len);
  729. }
  730. for(i=0; i<conf->logger_sz; i++)
  731. {
  732. logger = &(conf->loggers[i]);
  733. len = dprintf(logger->fd, conf->formats[logger->fmt_id]._msg);
  734. if(len < 0)
  735. {
  736. _syslog(LOG_ALERT,
  737. "Unable to write to single FD to '%s' when trying to log : %s",
  738. conf->loggers[i].filename, strerror(errno));
  739. ret = PYFCGI_FATAL;
  740. }
  741. }
  742. return ret;
  743. }