conf.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. * This file is part of the zlog Library.
  3. *
  4. * Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
  5. *
  6. * Licensed under the LGPL v2.1, see the file COPYING in base directory.
  7. */
  8. #include "fmacros.h"
  9. #include <ctype.h>
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <errno.h>
  13. #include <string.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <unistd.h>
  17. #include <time.h>
  18. #include "conf.h"
  19. #include "rule.h"
  20. #include "format.h"
  21. #include "level_list.h"
  22. #include "rotater.h"
  23. #include "zc_defs.h"
  24. /*******************************************************************************/
  25. #define ZLOG_CONF_DEFAULT_FORMAT "default = \"%D %V [%p:%F:%L] %m%n\""
  26. #define ZLOG_CONF_DEFAULT_RULE "*.* >stdout"
  27. #define ZLOG_CONF_DEFAULT_BUF_SIZE_MIN 1024
  28. #define ZLOG_CONF_DEFAULT_BUF_SIZE_MAX (2 * 1024 * 1024)
  29. #define ZLOG_CONF_DEFAULT_FILE_PERMS 0600
  30. #define ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD 0
  31. #define ZLOG_CONF_DEFAULT_FSYNC_PERIOD 0
  32. #define ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE "/tmp/zlog.lock"
  33. /*******************************************************************************/
  34. void zlog_conf_profile(zlog_conf_t * a_conf, int flag)
  35. {
  36. int i;
  37. zlog_rule_t *a_rule;
  38. zlog_format_t *a_format;
  39. zc_assert(a_conf,);
  40. zc_profile(flag, "-conf[%p]-", a_conf);
  41. zc_profile(flag, "--global--");
  42. zc_profile(flag, "---file[%s],mtime[%s]---", a_conf->file, a_conf->mtime);
  43. zc_profile(flag, "---in-memory conf[%s]---", a_conf->cfg_ptr);
  44. zc_profile(flag, "---strict init[%d]---", a_conf->strict_init);
  45. zc_profile(flag, "---buffer min[%ld]---", a_conf->buf_size_min);
  46. zc_profile(flag, "---buffer max[%ld]---", a_conf->buf_size_max);
  47. if (a_conf->default_format) {
  48. zc_profile(flag, "---default_format---");
  49. zlog_format_profile(a_conf->default_format, flag);
  50. }
  51. zc_profile(flag, "---file perms[0%o]---", a_conf->file_perms);
  52. zc_profile(flag, "---reload conf period[%ld]---", a_conf->reload_conf_period);
  53. zc_profile(flag, "---fsync period[%ld]---", a_conf->fsync_period);
  54. zc_profile(flag, "---rotate lock file[%s]---", a_conf->rotate_lock_file);
  55. if (a_conf->rotater) zlog_rotater_profile(a_conf->rotater, flag);
  56. if (a_conf->levels) zlog_level_list_profile(a_conf->levels, flag);
  57. if (a_conf->formats) {
  58. zc_profile(flag, "--format list[%p]--", a_conf->formats);
  59. zc_arraylist_foreach(a_conf->formats, i, a_format) {
  60. zlog_format_profile(a_format, flag);
  61. }
  62. }
  63. if (a_conf->rules) {
  64. zc_profile(flag, "--rule_list[%p]--", a_conf->rules);
  65. zc_arraylist_foreach(a_conf->rules, i, a_rule) {
  66. zlog_rule_profile(a_rule, flag);
  67. }
  68. }
  69. return;
  70. }
  71. /*******************************************************************************/
  72. void zlog_conf_del(zlog_conf_t * a_conf)
  73. {
  74. zc_assert(a_conf,);
  75. if (a_conf->rotater) zlog_rotater_del(a_conf->rotater);
  76. if (a_conf->levels) zlog_level_list_del(a_conf->levels);
  77. if (a_conf->default_format) zlog_format_del(a_conf->default_format);
  78. if (a_conf->formats) zc_arraylist_del(a_conf->formats);
  79. if (a_conf->rules) zc_arraylist_del(a_conf->rules);
  80. free(a_conf);
  81. zc_debug("zlog_conf_del[%p]");
  82. return;
  83. }
  84. static int zlog_conf_build_without_file(zlog_conf_t * a_conf);
  85. static int zlog_conf_build_with_file(zlog_conf_t * a_conf);
  86. static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf);
  87. enum{
  88. NO_CFG,
  89. FILE_CFG,
  90. IN_MEMORY_CFG
  91. };
  92. zlog_conf_t *zlog_conf_new(const char *config)
  93. {
  94. int nwrite = 0;
  95. int cfg_source = 0;
  96. zlog_conf_t *a_conf = NULL;
  97. a_conf = calloc(1, sizeof(zlog_conf_t));
  98. if (!a_conf) {
  99. zc_error("calloc fail, errno[%d]", errno);
  100. return NULL;
  101. }
  102. // Find content of pointer. If it starts with '[' then content are configurations.
  103. if (config && config[0] != '\0' && config[0] != '[') {
  104. nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", config);
  105. cfg_source = FILE_CFG;
  106. } else if (getenv("ZLOG_CONF_PATH") != NULL) {
  107. nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", getenv("ZLOG_CONF_PATH"));
  108. cfg_source = FILE_CFG;
  109. } else if (config[0]=='[') {
  110. memset(a_conf->file, 0x00, sizeof(a_conf->file));
  111. nwrite = snprintf(a_conf->cfg_ptr, sizeof(a_conf->cfg_ptr), "%s", config);
  112. cfg_source = IN_MEMORY_CFG;
  113. if (nwrite < 0 || nwrite >= sizeof(a_conf->file)) {
  114. zc_error("not enough space for configurations, nwrite=[%d], errno[%d]", nwrite, errno);
  115. goto err;
  116. }
  117. } else {
  118. memset(a_conf->file, 0x00, sizeof(a_conf->file));
  119. cfg_source = NO_CFG;
  120. }
  121. if (nwrite < 0 || nwrite >= sizeof(a_conf->file) && cfg_source == FILE_CFG) {
  122. zc_error("not enough space for path name, nwrite=[%d], errno[%d]", nwrite, errno);
  123. goto err;
  124. }
  125. /* set default configuration start */
  126. a_conf->strict_init = 1;
  127. a_conf->buf_size_min = ZLOG_CONF_DEFAULT_BUF_SIZE_MIN;
  128. a_conf->buf_size_max = ZLOG_CONF_DEFAULT_BUF_SIZE_MAX;
  129. if (cfg_source == FILE_CFG) {
  130. /* configure file as default lock file */
  131. strcpy(a_conf->rotate_lock_file, a_conf->file);
  132. } else {
  133. strcpy(a_conf->rotate_lock_file, ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE);
  134. }
  135. strcpy(a_conf->default_format_line, ZLOG_CONF_DEFAULT_FORMAT);
  136. a_conf->file_perms = ZLOG_CONF_DEFAULT_FILE_PERMS;
  137. a_conf->reload_conf_period = ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD;
  138. a_conf->fsync_period = ZLOG_CONF_DEFAULT_FSYNC_PERIOD;
  139. /* set default configuration end */
  140. a_conf->levels = zlog_level_list_new();
  141. if (!a_conf->levels) {
  142. zc_error("zlog_level_list_new fail");
  143. goto err;
  144. }
  145. a_conf->formats = zc_arraylist_new((zc_arraylist_del_fn) zlog_format_del);
  146. if (!a_conf->formats) {
  147. zc_error("zc_arraylist_new fail");
  148. goto err;
  149. }
  150. a_conf->rules = zc_arraylist_new((zc_arraylist_del_fn) zlog_rule_del);
  151. if (!a_conf->rules) {
  152. zc_error("init rule_list fail");
  153. goto err;
  154. }
  155. if (cfg_source == FILE_CFG) {
  156. if (zlog_conf_build_with_file(a_conf)) {
  157. zc_error("zlog_conf_build_with_file fail");
  158. goto err;
  159. }
  160. } else if (cfg_source == IN_MEMORY_CFG) {
  161. if(zlog_conf_build_with_in_memory(a_conf)){
  162. zc_error("zlog_conf_build_with_in_memory fail");
  163. goto err;
  164. }
  165. } else {
  166. if (zlog_conf_build_without_file(a_conf)) {
  167. zc_error("zlog_conf_build_without_file fail");
  168. goto err;
  169. }
  170. }
  171. zlog_conf_profile(a_conf, ZC_DEBUG);
  172. return a_conf;
  173. err:
  174. zlog_conf_del(a_conf);
  175. return NULL;
  176. }
  177. /*******************************************************************************/
  178. static int zlog_conf_build_without_file(zlog_conf_t * a_conf)
  179. {
  180. zlog_rule_t *default_rule;
  181. a_conf->default_format = zlog_format_new(a_conf->default_format_line, &(a_conf->time_cache_count));
  182. if (!a_conf->default_format) {
  183. zc_error("zlog_format_new fail");
  184. return -1;
  185. }
  186. a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file);
  187. if (!a_conf->rotater) {
  188. zc_error("zlog_rotater_new fail");
  189. return -1;
  190. }
  191. default_rule = zlog_rule_new(
  192. ZLOG_CONF_DEFAULT_RULE,
  193. a_conf->levels,
  194. a_conf->default_format,
  195. a_conf->formats,
  196. a_conf->file_perms,
  197. a_conf->fsync_period,
  198. &(a_conf->time_cache_count));
  199. if (!default_rule) {
  200. zc_error("zlog_rule_new fail");
  201. return -1;
  202. }
  203. /* add default rule */
  204. if (zc_arraylist_add(a_conf->rules, default_rule)) {
  205. zlog_rule_del(default_rule);
  206. zc_error("zc_arraylist_add fail");
  207. return -1;
  208. }
  209. return 0;
  210. }
  211. /*******************************************************************************/
  212. static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section);
  213. static int zlog_conf_build_with_file(zlog_conf_t * a_conf)
  214. {
  215. int rc = 0;
  216. struct zlog_stat a_stat;
  217. struct tm local_time;
  218. FILE *fp = NULL;
  219. char line[MAXLEN_CFG_LINE + 1];
  220. size_t line_len;
  221. char *pline = NULL;
  222. char *p = NULL;
  223. int line_no = 0;
  224. int i = 0;
  225. int in_quotation = 0;
  226. int section = 0;
  227. /* [global:1] [levels:2] [formats:3] [rules:4] */
  228. if (lstat(a_conf->file, &a_stat)) {
  229. zc_error("lstat conf file[%s] fail, errno[%d]", a_conf->file,
  230. errno);
  231. return -1;
  232. }
  233. localtime_r(&(a_stat.st_mtime), &local_time);
  234. strftime(a_conf->mtime, sizeof(a_conf->mtime), "%F %T", &local_time);
  235. if ((fp = fopen(a_conf->file, "r")) == NULL) {
  236. zc_error("open configure file[%s] fail", a_conf->file);
  237. return -1;
  238. }
  239. /* Now process the file.
  240. */
  241. pline = line;
  242. memset(&line, 0x00, sizeof(line));
  243. while (fgets((char *)pline, sizeof(line) - (pline - line), fp) != NULL) {
  244. ++line_no;
  245. line_len = strlen(pline);
  246. if (0 == line_len) {
  247. continue;
  248. }
  249. if (pline[line_len - 1] == '\n') {
  250. pline[line_len - 1] = '\0';
  251. }
  252. /* check for end-of-section, comments, strip off trailing
  253. * spaces and newline character.
  254. */
  255. p = pline;
  256. while (*p && isspace((int)*p))
  257. ++p;
  258. if (*p == '\0' || *p == '#')
  259. continue;
  260. for (i = 0; p[i] != '\0'; ++i) {
  261. pline[i] = p[i];
  262. }
  263. pline[i] = '\0';
  264. for (p = pline + strlen(pline) - 1; isspace((int)*p); --p)
  265. /*EMPTY*/;
  266. if (*p == '\\') {
  267. if ((p - line) > MAXLEN_CFG_LINE - 30) {
  268. /* Oops the buffer is full - what now? */
  269. pline = line;
  270. } else {
  271. for (p--; isspace((int)*p); --p)
  272. /*EMPTY*/;
  273. p++;
  274. *p = 0;
  275. pline = p;
  276. continue;
  277. }
  278. } else
  279. pline = line;
  280. *++p = '\0';
  281. /* clean the tail comments start from # and not in quotation */
  282. in_quotation = 0;
  283. for (p = line; *p != '\0'; p++) {
  284. if (*p == '"') {
  285. in_quotation ^= 1;
  286. continue;
  287. }
  288. if (*p == '#' && !in_quotation) {
  289. *p = '\0';
  290. break;
  291. }
  292. }
  293. /* we now have the complete line,
  294. * and are positioned at the first non-whitespace
  295. * character. So let's process it
  296. */
  297. rc = zlog_conf_parse_line(a_conf, line, &section);
  298. if (rc < 0) {
  299. zc_error("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
  300. zc_error("line[%s]", line);
  301. goto exit;
  302. } else if (rc > 0) {
  303. zc_warn("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
  304. zc_warn("line[%s]", line);
  305. zc_warn("as strict init is set to false, ignore and go on");
  306. rc = 0;
  307. continue;
  308. }
  309. }
  310. exit:
  311. fclose(fp);
  312. return rc;
  313. }
  314. /**********************************************************************/
  315. static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf)
  316. {
  317. int rc = 0;
  318. char line[MAXLEN_CFG_LINE + 1];
  319. char *pline = NULL;
  320. int section = 0;
  321. pline = line;
  322. memset(&line, 0x00, sizeof(line));
  323. pline = strtok((char *)a_conf->cfg_ptr, "\n");
  324. while (pline != NULL) {
  325. rc = zlog_conf_parse_line(a_conf, pline, &section);
  326. if (rc < 0) {
  327. zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline);
  328. break;
  329. } else if (rc > 0) {
  330. zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline);
  331. zc_warn("as strict init is set to false, ignore and go on");
  332. rc = 0;
  333. continue;
  334. }
  335. pline = strtok(NULL, "\n");
  336. }
  337. return rc;
  338. }
  339. /* section [global:1] [levels:2] [formats:3] [rules:4] */
  340. static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section)
  341. {
  342. int nscan;
  343. int nread;
  344. char name[MAXLEN_CFG_LINE + 1];
  345. char word_1[MAXLEN_CFG_LINE + 1];
  346. char word_2[MAXLEN_CFG_LINE + 1];
  347. char word_3[MAXLEN_CFG_LINE + 1];
  348. char value[MAXLEN_CFG_LINE + 1];
  349. zlog_format_t *a_format = NULL;
  350. zlog_rule_t *a_rule = NULL;
  351. if (strlen(line) > MAXLEN_CFG_LINE) {
  352. zc_error ("line_len[%ld] > MAXLEN_CFG_LINE[%ld], may cause overflow",
  353. strlen(line), MAXLEN_CFG_LINE);
  354. return -1;
  355. }
  356. /* get and set outer section flag, so it is a closure? haha */
  357. if (line[0] == '[') {
  358. int last_section = *section;
  359. nscan = sscanf(line, "[ %[^] \t]", name);
  360. if (STRCMP(name, ==, "global")) {
  361. *section = 1;
  362. } else if (STRCMP(name, ==, "levels")) {
  363. *section = 2;
  364. } else if (STRCMP(name, ==, "formats")) {
  365. *section = 3;
  366. } else if (STRCMP(name, ==, "rules")) {
  367. *section = 4;
  368. } else {
  369. zc_error("wrong section name[%s]", name);
  370. return -1;
  371. }
  372. /* check the sequence of section, must increase */
  373. if (last_section >= *section) {
  374. zc_error("wrong sequence of section, must follow global->levels->formats->rules");
  375. return -1;
  376. }
  377. if (*section == 4) {
  378. if (a_conf->reload_conf_period != 0
  379. && a_conf->fsync_period >= a_conf->reload_conf_period) {
  380. /* as all rule will be rebuilt when conf is reload,
  381. * so fsync_period > reload_conf_period will never
  382. * cause rule to fsync it's file.
  383. * fsync_period will be meaningless and down speed,
  384. * so make it zero.
  385. */
  386. zc_warn("fsync_period[%ld] >= reload_conf_period[%ld],"
  387. "set fsync_period to zero");
  388. a_conf->fsync_period = 0;
  389. }
  390. /* now build rotater and default_format
  391. * from the unchanging global setting,
  392. * for zlog_rule_new() */
  393. a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file);
  394. if (!a_conf->rotater) {
  395. zc_error("zlog_rotater_new fail");
  396. return -1;
  397. }
  398. a_conf->default_format = zlog_format_new(a_conf->default_format_line,
  399. &(a_conf->time_cache_count));
  400. if (!a_conf->default_format) {
  401. zc_error("zlog_format_new fail");
  402. return -1;
  403. }
  404. }
  405. return 0;
  406. }
  407. /* process detail */
  408. switch (*section) {
  409. case 1:
  410. memset(name, 0x00, sizeof(name));
  411. memset(value, 0x00, sizeof(value));
  412. nscan = sscanf(line, " %[^=]= %s ", name, value);
  413. if (nscan != 2) {
  414. zc_error("sscanf [%s] fail, name or value is null", line);
  415. return -1;
  416. }
  417. memset(word_1, 0x00, sizeof(word_1));
  418. memset(word_2, 0x00, sizeof(word_2));
  419. memset(word_3, 0x00, sizeof(word_3));
  420. nread = 0;
  421. nscan = sscanf(name, "%s%n%s%s", word_1, &nread, word_2, word_3);
  422. if (STRCMP(word_1, ==, "strict") && STRCMP(word_2, ==, "init")) {
  423. /* if environment variable ZLOG_STRICT_INIT is set
  424. * then always make it strict
  425. */
  426. if (STRICMP(value, ==, "false") && !getenv("ZLOG_STRICT_INIT")) {
  427. a_conf->strict_init = 0;
  428. } else {
  429. a_conf->strict_init = 1;
  430. }
  431. } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "min")) {
  432. a_conf->buf_size_min = zc_parse_byte_size(value);
  433. } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "max")) {
  434. a_conf->buf_size_max = zc_parse_byte_size(value);
  435. } else if (STRCMP(word_1, ==, "file") && STRCMP(word_2, ==, "perms")) {
  436. sscanf(value, "%o", &(a_conf->file_perms));
  437. } else if (STRCMP(word_1, ==, "rotate") &&
  438. STRCMP(word_2, ==, "lock") && STRCMP(word_3, ==, "file")) {
  439. /* may overwrite the inner default value, or last value */
  440. if (STRCMP(value, ==, "self")) {
  441. strcpy(a_conf->rotate_lock_file, a_conf->file);
  442. } else {
  443. strcpy(a_conf->rotate_lock_file, value);
  444. }
  445. } else if (STRCMP(word_1, ==, "default") && STRCMP(word_2, ==, "format")) {
  446. /* so the input now is [format = "xxyy"], fit format's style */
  447. strcpy(a_conf->default_format_line, line + nread);
  448. } else if (STRCMP(word_1, ==, "reload") &&
  449. STRCMP(word_2, ==, "conf") && STRCMP(word_3, ==, "period")) {
  450. a_conf->reload_conf_period = zc_parse_byte_size(value);
  451. } else if (STRCMP(word_1, ==, "fsync") && STRCMP(word_2, ==, "period")) {
  452. a_conf->fsync_period = zc_parse_byte_size(value);
  453. } else {
  454. zc_error("name[%s] is not any one of global options", name);
  455. if (a_conf->strict_init) return -1;
  456. }
  457. break;
  458. case 2:
  459. if (zlog_level_list_set(a_conf->levels, line)) {
  460. zc_error("zlog_level_list_set fail");
  461. if (a_conf->strict_init) return -1;
  462. }
  463. break;
  464. case 3:
  465. a_format = zlog_format_new(line, &(a_conf->time_cache_count));
  466. if (!a_format) {
  467. zc_error("zlog_format_new fail [%s]", line);
  468. if (a_conf->strict_init) return -1;
  469. else break;
  470. }
  471. if (zc_arraylist_add(a_conf->formats, a_format)) {
  472. zlog_format_del(a_format);
  473. zc_error("zc_arraylist_add fail");
  474. return -1;
  475. }
  476. break;
  477. case 4:
  478. a_rule = zlog_rule_new(line,
  479. a_conf->levels,
  480. a_conf->default_format,
  481. a_conf->formats,
  482. a_conf->file_perms,
  483. a_conf->fsync_period,
  484. &(a_conf->time_cache_count));
  485. if (!a_rule) {
  486. zc_error("zlog_rule_new fail [%s]", line);
  487. if (a_conf->strict_init) return -1;
  488. else break;
  489. }
  490. if (zc_arraylist_add(a_conf->rules, a_rule)) {
  491. zlog_rule_del(a_rule);
  492. zc_error("zc_arraylist_add fail");
  493. return -1;
  494. }
  495. break;
  496. default:
  497. zc_error("not in any section");
  498. return -1;
  499. }
  500. return 0;
  501. }
  502. /*******************************************************************************/