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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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. unsigned int 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,
  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. else
  311. {
  312. break;
  313. }
  314. }
  315. return 0;
  316. }
  317. int pyfcgi_logger_parse_field(const char** ptr, const char *start,
  318. pyfcgi_logger_fmt_field_t* cur_field,
  319. char fail_reason[PYFCGI_LOGGER_FMT_PARSE_ERRSZ])
  320. {
  321. const char *str_start, *field_start;
  322. int ret;
  323. char **name, *cname, **format;
  324. size_t default_len;
  325. pyfcgi_logger_field_type_e *type;
  326. char *field_names[] = {"datetime", "level", "facility", "pid", "ident",
  327. "msg", NULL};
  328. pyfcgi_logger_field_type_e field_types[] = {
  329. pyfcgi_logger_field_datetime, pyfcgi_logger_field_level,
  330. pyfcgi_logger_field_facility, pyfcgi_logger_field_pid,
  331. pyfcgi_logger_field_ident, pyfcgi_logger_field_msg};
  332. str_start = *ptr;
  333. field_start = *ptr;
  334. name = field_names;
  335. type = field_types;
  336. while(*name)
  337. {
  338. cname = *name;
  339. if(*cname != **ptr)
  340. {
  341. name++;
  342. type++;
  343. continue;
  344. }
  345. // Name found ?
  346. while(**ptr && *cname && **ptr != ':' && **ptr != '}' &&
  347. **ptr == *cname)
  348. {
  349. (*ptr)++;
  350. cname++;
  351. }
  352. if(**ptr == ':' || **ptr == '}')
  353. {
  354. cur_field->type = *type;
  355. break;
  356. }
  357. else
  358. {
  359. *name = field_names[6]; // NULL
  360. break;
  361. }
  362. }
  363. if(!name)
  364. {
  365. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  366. "unknown field type '%s' chr %ld",
  367. str_start, str_start - start);
  368. return 1;
  369. }
  370. if(**ptr == ':') { (*ptr)++; } // next option
  371. if(pyfcgi_logger_parse_field_sz(ptr, &(cur_field->len)))
  372. {
  373. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  374. "Unable to parse field size chr %ld '%s'",
  375. str_start - start, str_start);
  376. return 1;
  377. }
  378. if(**ptr == ':') { (*ptr)++; } // next option
  379. str_start = *ptr;
  380. cur_field->known_length = 1;
  381. switch(cur_field->type)
  382. {
  383. case pyfcgi_logger_field_datetime:
  384. default_len = PYFCGI_LOG_DTM_LEN;
  385. cur_field->val = (void*)strftime;
  386. format = &(cur_field->args.datetime.format);
  387. ret = pyfcgi_logger_parse_field_dtfmt(ptr,format);
  388. if(ret){
  389. return ret;
  390. }
  391. break;
  392. case pyfcgi_logger_field_level:
  393. default_len = PYFCGI_LOG_LVL_LEN;
  394. cur_field->val = (void*)pyfcgi_logger_value_level;
  395. break;
  396. case pyfcgi_logger_field_facility:
  397. default_len = PYFCGI_LOG_TYP_LEN;
  398. cur_field->val = (void*)pyfcgi_logger_value_facility;
  399. break;
  400. case pyfcgi_logger_field_pid:
  401. default_len = PYFCGI_LOG_PID_LEN-1;
  402. cur_field->val = &(PyFCGI_conf.context.pid);
  403. break;
  404. case pyfcgi_logger_field_ident:
  405. default_len = PyFCGI_conf.logs.ident?strlen(PyFCGI_conf.logs.ident):0;
  406. cur_field->val = &(PyFCGI_conf.logs.ident);
  407. break;
  408. case pyfcgi_logger_field_msg:
  409. cur_field->known_length = 0;
  410. default_len = 0;
  411. break;
  412. default:
  413. snprintf(fail_reason, PYFCGI_LOGGER_FMT_PARSE_ERRSZ,
  414. "Unknown error parsing field '%s' at chr %ld",
  415. field_start , *ptr - start);
  416. return 1;
  417. }
  418. if(!cur_field->len && default_len)
  419. {
  420. cur_field->len = default_len;
  421. }
  422. return 0;
  423. }
  424. void pyfcgi_logger_field_free(pyfcgi_logger_fmt_field_t* field)
  425. {
  426. switch(field->type)
  427. {
  428. case pyfcgi_logger_field_const:
  429. if(field->val)
  430. {
  431. free(field->val);
  432. }
  433. break;
  434. case pyfcgi_logger_field_datetime:
  435. if(field->args.datetime.format)
  436. {
  437. free(field->args.datetime.format);
  438. }
  439. break;
  440. case pyfcgi_logger_field_null:
  441. case pyfcgi_logger_field_level:
  442. case pyfcgi_logger_field_facility:
  443. case pyfcgi_logger_field_pid:
  444. case pyfcgi_logger_field_ppid:
  445. case pyfcgi_logger_field_ident:
  446. case pyfcgi_logger_field_msg:
  447. break;
  448. }
  449. }
  450. int pyfcgi_logger_parse_field_dtfmt(const char** ptr, char** format)
  451. {
  452. const char *fmt;
  453. size_t fmt_len;
  454. fmt_len = 0;
  455. fmt = *ptr;
  456. while(**ptr && **ptr != '}' && *((*ptr)+1) != '}')
  457. {
  458. (*ptr)++;
  459. fmt_len++;
  460. }
  461. if(!(**ptr))
  462. {
  463. //TODO error
  464. }
  465. if(!fmt_len)
  466. {
  467. fmt_len = sizeof(PYFCGI_LOGGER_TIME_FMT_DEFAULT);
  468. fmt = PYFCGI_LOGGER_TIME_FMT_DEFAULT;
  469. }
  470. if(!(*format = strndup(fmt, fmt_len+1)))
  471. {
  472. pyfcgi_log(LOG_ALERT,
  473. "Unable to strdup field datetime format : %s",
  474. strerror(errno));
  475. return PYFCGI_FATAL;
  476. }
  477. return 0;
  478. }
  479. int pyfcgi_logger_parse_field_sz(const char **ptr, size_t *size)
  480. {
  481. char *end;
  482. *size = 0;
  483. if(**ptr == '}' || **ptr == ':')
  484. {
  485. return 0;
  486. }
  487. if(**ptr < '0' || **ptr > '9')
  488. {
  489. return 1; // parse error
  490. }
  491. *size = strtoull(*ptr, &end, 10);
  492. *ptr = end;
  493. return 0;
  494. }
  495. const char* pyfcgi_logger_value_level(short lvl)
  496. {
  497. short idx;
  498. idx = ((lvl & 0xF0) >> 4)-1;
  499. if(idx < 0 || idx > 7)
  500. {
  501. return NULL;
  502. }
  503. return PYFCGI_LOGGER_LVLNAME[idx];
  504. }
  505. const char* pyfcgi_logger_value_facility(short typ)
  506. {
  507. short idx;
  508. idx = typ & 0x0F;
  509. if(idx < 0 || idx >= sizeof(PYFCGI_LOGGER_TYPNAME))
  510. {
  511. return NULL;
  512. }
  513. return PYFCGI_LOGGER_TYPNAME[idx];
  514. }
  515. int pyfcgi_logger_open(pyfcgi_logger_t *logger)
  516. {
  517. int flags;
  518. if(!logger->filename)
  519. {
  520. logger->fd = 2;
  521. flags = fcntl(logger->fd, F_GETFL);
  522. if(flags == -1)
  523. {
  524. pyfcgi_log(LOG_ERR,
  525. "Unable to GETFL on stderr",
  526. strerror(errno));
  527. return PYFCGI_ERR;
  528. }
  529. flags |= O_NONBLOCK;
  530. if(fcntl(logger->fd, F_SETFL, flags) == -1)
  531. {
  532. pyfcgi_log(LOG_ERR,
  533. "Unable to SETFL on stderr",
  534. strerror(errno));
  535. return PYFCGI_ERR;
  536. }
  537. return 0;
  538. }
  539. if( ((logger->fd = open(logger->filename,
  540. O_WRONLY | O_APPEND | O_CREAT, 00640)) < 0) )
  541. {
  542. pyfcgi_log(LOG_ERR,
  543. "Unable to open log file '%s' : %s",
  544. strerror(errno));
  545. return PYFCGI_ERR;
  546. }
  547. return 0;
  548. }
  549. int pyfcgi_logger_set_ident(const char* new_ident)
  550. {
  551. pyfcgi_conf_logger_t *conf;
  552. pyfcgi_logger_format_t *fmt;
  553. pyfcgi_logger_fmt_field_t *field;
  554. size_t i, j, len;
  555. short upd;
  556. conf = &PyFCGI_conf.logs;
  557. if(conf->ident)
  558. {
  559. free(conf->ident);
  560. }
  561. if( !(conf->ident = strdup(new_ident)) )
  562. {
  563. pyfcgi_log(LOG_ALERT,
  564. "Error duplicating identity for logger : %s",
  565. strerror(errno));
  566. return PYFCGI_FATAL;
  567. }
  568. if(conf->flags & PYFCGI_LOG_FSYSLOG)
  569. {
  570. pyfcgi_logger_enable_syslog(new_ident);
  571. }
  572. len = strlen(conf->ident);
  573. for(i=0; i<conf->format_sz; i++)
  574. {
  575. fmt = &(conf->formats[i]);
  576. upd = 0;
  577. for(j=0; j<fmt->nfield; j++)
  578. {
  579. field = &(fmt->fields[j]);
  580. if(field->type == pyfcgi_logger_field_ident)
  581. {
  582. field->len = len;
  583. upd = 1;
  584. }
  585. }
  586. if(upd)
  587. {
  588. pyfcgi_logger_format_bufinit(fmt);
  589. }
  590. }
  591. return 0;
  592. }
  593. char* vpyfcgi_logger_format_message(pyfcgi_logger_format_t *fmt,
  594. loglvl_t lvl, const char* message, size_t fmt_msg_len)
  595. {
  596. /**@todo Add '\n' when suffix is used ! */
  597. char *_msgptr;
  598. size_t maxlen;
  599. int ret;
  600. void *tmp;
  601. size_t i, suff_off;
  602. pyfcgi_logger_fmt_field_t *field;
  603. struct tm *curtime;
  604. time_t _curtime;
  605. size_t (*_strftime)(char*, size_t, const char*, const struct tm*);
  606. if(!fmt->_msg)
  607. { //first message, allocating message buffer
  608. fmt->_msglen = fmt->buflen[0] + fmt->buflen[1] + fmt_msg_len + 1;
  609. // rounding upper
  610. fmt->_msglen >>= 6;
  611. fmt->_msglen++;
  612. fmt->_msglen <<= 6;
  613. fmt->_msg = malloc(sizeof(char) * fmt->_msglen);
  614. if(!fmt->_msg)
  615. {
  616. //TODO : error
  617. dprintf(2, "ERROR ALLOC _msg : %s\n", strerror(errno));
  618. return NULL;
  619. }
  620. memset(fmt->_msg, ' ', sizeof(char)*fmt->_msglen);
  621. fmt->_msg[fmt->_msglen - 1] = '\0';
  622. memcpy(fmt->_msg, fmt->prefix, fmt->buflen[0]);
  623. }
  624. while(1)
  625. {
  626. maxlen = fmt->_msglen - (fmt->buflen[0] + fmt->buflen[1]);
  627. if(fmt_msg_len < maxlen)
  628. {
  629. // TODO check errors
  630. break;
  631. }
  632. fmt->_msglen = fmt_msg_len + fmt->buflen[0] + fmt->buflen[1] + 1;
  633. fmt->_msglen >>= 6;
  634. fmt->_msglen++;
  635. fmt->_msglen <<= 6;
  636. tmp = realloc(fmt->_msg, sizeof(char) * fmt->_msglen);
  637. if(!tmp)
  638. {
  639. //TODO : error
  640. dprintf(2, "ERROR REALLOC _msg : %s", strerror(errno));
  641. return NULL;
  642. }
  643. fmt->_msg = tmp;
  644. }
  645. memcpy(fmt->_msg + fmt->buflen[0], message, fmt_msg_len);
  646. suff_off = fmt->buflen[0] + fmt_msg_len;
  647. if(fmt->buflen[1])
  648. {
  649. strncpy(fmt->_msg + suff_off, fmt->suffix,
  650. fmt->buflen[1]);
  651. //TODO check errors
  652. fmt->_msg[suff_off+fmt->buflen[1]-1] = '\n';
  653. fmt->_msg[suff_off+fmt->buflen[1]] = '\0';
  654. }
  655. else
  656. {
  657. fmt->_msg[suff_off] = '\n';
  658. fmt->_msg[suff_off+1] = '\0';
  659. }
  660. // update fmt->_msg dynamic fields
  661. time(&_curtime);
  662. curtime = localtime(&_curtime);
  663. for(i=0; i<fmt->nfield; i++)
  664. {
  665. field = &(fmt->fields[i]);
  666. _msgptr = fmt->_msg;
  667. _msgptr += field->suff?suff_off:0;
  668. _msgptr += field->buf_off;
  669. switch(field->type)
  670. {
  671. case pyfcgi_logger_field_datetime:
  672. _strftime = field->val?field->val:strftime;
  673. ret = _strftime(_msgptr, field->len,
  674. field->args.datetime.format,
  675. curtime);
  676. if(!ret)
  677. {
  678. //TODO ERROR
  679. dprintf(2,"Not enough space to write datetime in '%s', need more than %ld\n",
  680. fmt->fmt, field->len);
  681. }
  682. _msgptr[ret] = ' ';
  683. break;
  684. case pyfcgi_logger_field_level:
  685. memcpy(_msgptr,
  686. pyfcgi_logger_value_level(lvl),
  687. field->len);
  688. break;
  689. default:
  690. break;
  691. }
  692. }
  693. return fmt->_msg;
  694. }
  695. int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
  696. {
  697. int ret;
  698. va_list ap;
  699. va_start(ap, fmt);
  700. ret = vpyfcgi_log(lvl, fmt, ap);
  701. va_end(ap);
  702. return ret;
  703. }
  704. int vpyfcgi_log(loglvl_t lvl, const char *fmt, va_list ap)
  705. {
  706. int len, ret;
  707. pyfcgi_conf_logger_t *conf;
  708. pyfcgi_logger_t *logger;
  709. unsigned char i;
  710. size_t msglen, real_len;
  711. void *tmp;
  712. va_list o_ap;
  713. conf = &PyFCGI_conf.logs;
  714. va_copy(o_ap, ap);
  715. _vsyslog(lvl, fmt, o_ap);
  716. va_end(o_ap);
  717. ret = 0;
  718. // processing message before sending it to formats
  719. while(1)
  720. {
  721. va_copy(o_ap, ap);
  722. msglen = vsnprintf(conf->msg_buf, conf->msg_buf_sz, fmt, o_ap);
  723. real_len = msglen;
  724. va_end(o_ap);
  725. // Rounding msglen
  726. msglen >>=6;
  727. msglen++;
  728. msglen <<=6;
  729. if(msglen <= conf->msg_buf_sz)
  730. {
  731. break;
  732. }
  733. conf->msg_buf_sz = msglen;
  734. tmp = realloc(conf->msg_buf,
  735. sizeof(char)*conf->msg_buf_sz);
  736. if(!tmp)
  737. {
  738. // TODO : error
  739. dprintf(2, "ERROR REALLOC conf_msg : %s", strerror(errno));
  740. if(conf->msg_buf) { free(conf->msg_buf); }
  741. return PYFCGI_FATAL;
  742. }
  743. conf->msg_buf = tmp;
  744. }
  745. // populating format messages
  746. for(i=0; i<conf->format_sz; i++)
  747. {
  748. vpyfcgi_logger_format_message(&(conf->formats[i]), lvl,
  749. conf->msg_buf, real_len);
  750. }
  751. for(i=0; i<conf->logger_sz; i++)
  752. {
  753. logger = &(conf->loggers[i]);
  754. len = dprintf(logger->fd, conf->formats[logger->fmt_id]._msg);
  755. if(len < 0)
  756. {
  757. _syslog(LOG_ALERT,
  758. "Unable to write to single FD to '%s' when trying to log : %s",
  759. conf->loggers[i].filename, strerror(errno));
  760. ret = PYFCGI_FATAL;
  761. }
  762. }
  763. return ret;
  764. }