log2journal-help.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "log2journal.h"
  3. static void config_dir_print_available(void) {
  4. const char *path = LOG2JOURNAL_CONFIG_PATH;
  5. DIR *dir;
  6. struct dirent *entry;
  7. dir = opendir(path);
  8. if (dir == NULL) {
  9. log2stderr(" >>> Cannot open directory:\n %s", path);
  10. return;
  11. }
  12. size_t column_width = 80;
  13. size_t current_columns = 7; // Start with 7 spaces for the first line
  14. while ((entry = readdir(dir))) {
  15. if (entry->d_type == DT_REG) { // Check if it's a regular file
  16. const char *file_name = entry->d_name;
  17. size_t len = strlen(file_name);
  18. if (len >= 5 && strcmp(file_name + len - 5, ".yaml") == 0) {
  19. // Remove the ".yaml" extension
  20. len -= 5;
  21. if (current_columns == 7) {
  22. printf(" "); // Print 7 spaces at the beginning of a new line
  23. }
  24. if (current_columns + len + 1 > column_width) {
  25. // Start a new line if the current line is full
  26. printf("\n "); // Print newline and 7 spaces
  27. current_columns = 7;
  28. }
  29. printf("%.*s ", (int)len, file_name); // Print the filename without extension
  30. current_columns += len + 1; // Add filename length and a space
  31. }
  32. }
  33. }
  34. closedir(dir);
  35. printf("\n"); // Add a newline at the end
  36. }
  37. void log_job_command_line_help(const char *name) {
  38. printf("\n");
  39. printf("Netdata log2journal " PACKAGE_VERSION "\n");
  40. printf("\n");
  41. printf("Convert logs to systemd Journal Export Format.\n");
  42. printf("\n");
  43. printf(" - JSON logs: extracts all JSON fields.\n");
  44. printf(" - logfmt logs: extracts all logfmt fields.\n");
  45. printf(" - free-form logs: uses PCRE2 patterns to extracts fields.\n");
  46. printf("\n");
  47. printf("Usage: %s [OPTIONS] PATTERN|json\n", name);
  48. printf("\n");
  49. printf("Options:\n");
  50. printf("\n");
  51. #ifdef HAVE_LIBYAML
  52. printf(" --file /path/to/file.yaml or -f /path/to/file.yaml\n");
  53. printf(" Read yaml configuration file for instructions.\n");
  54. printf("\n");
  55. printf(" --config CONFIG_NAME or -c CONFIG_NAME\n");
  56. printf(" Run with the internal YAML configuration named CONFIG_NAME.\n");
  57. printf(" Available internal YAML configs:\n");
  58. printf("\n");
  59. config_dir_print_available();
  60. printf("\n");
  61. #else
  62. printf(" IMPORTANT:\n");
  63. printf(" YAML configuration parsing is not compiled in this binary.\n");
  64. printf("\n");
  65. #endif
  66. printf("--------------------------------------------------------------------------------\n");
  67. printf(" INPUT PROCESSING\n");
  68. printf("\n");
  69. printf(" PATTERN\n");
  70. printf(" PATTERN should be a valid PCRE2 regular expression.\n");
  71. printf(" RE2 regular expressions (like the ones usually used in Go applications),\n");
  72. printf(" are usually valid PCRE2 patterns too.\n");
  73. printf(" Sub-expressions without named groups are evaluated, but their matches are\n");
  74. printf(" not added to the output.\n");
  75. printf("\n");
  76. printf(" - JSON mode\n");
  77. printf(" JSON mode is enabled when the pattern is set to: json\n");
  78. printf(" Field names are extracted from the JSON logs and are converted to the\n");
  79. printf(" format expected by Journal Export Format (all caps, only _ is allowed).\n");
  80. printf("\n");
  81. printf(" - logfmt mode\n");
  82. printf(" logfmt mode is enabled when the pattern is set to: logfmt\n");
  83. printf(" Field names are extracted from the logfmt logs and are converted to the\n");
  84. printf(" format expected by Journal Export Format (all caps, only _ is allowed).\n");
  85. printf("\n");
  86. printf(" All keys extracted from the input, are transliterated to match Journal\n");
  87. printf(" semantics (capital A-Z, digits 0-9, underscore).\n");
  88. printf("\n");
  89. printf(" In a YAML file:\n");
  90. printf(" ```yaml\n");
  91. printf(" pattern: 'PCRE2 pattern | json | logfmt'\n");
  92. printf(" ```\n");
  93. printf("\n");
  94. printf("--------------------------------------------------------------------------------\n");
  95. printf(" GLOBALS\n");
  96. printf("\n");
  97. printf(" --prefix PREFIX\n");
  98. printf(" Prefix all fields with PREFIX. The PREFIX is added before any other\n");
  99. printf(" processing, so that the extracted keys have to be matched with the PREFIX in\n");
  100. printf(" them. PREFIX is NOT transliterated and it is assumed to be systemd-journal\n");
  101. printf(" friendly.\n");
  102. printf("\n");
  103. printf(" In a YAML file:\n");
  104. printf(" ```yaml\n");
  105. printf(" prefix: 'PREFIX_' # prepend all keys with this prefix.\n");
  106. printf(" ```\n");
  107. printf("\n");
  108. printf(" --filename-key KEY\n");
  109. printf(" Add a field with KEY as the key and the current filename as value.\n");
  110. printf(" Automatically detects filenames when piped after 'tail -F',\n");
  111. printf(" and tail matches multiple filenames.\n");
  112. printf(" To inject the filename when tailing a single file, use --inject.\n");
  113. printf("\n");
  114. printf(" In a YAML file:\n");
  115. printf(" ```yaml\n");
  116. printf(" filename:\n");
  117. printf(" key: KEY\n");
  118. printf(" ```\n");
  119. printf("\n");
  120. printf("--------------------------------------------------------------------------------\n");
  121. printf(" RENAMING OF KEYS\n");
  122. printf("\n");
  123. printf(" --rename NEW=OLD\n");
  124. printf(" Rename fields. OLD has been transliterated and PREFIX has been added.\n");
  125. printf(" NEW is assumed to be systemd journal friendly.\n");
  126. printf("\n");
  127. printf(" Up to %d renaming rules are allowed.\n", MAX_RENAMES);
  128. printf("\n");
  129. printf(" In a YAML file:\n");
  130. printf(" ```yaml\n");
  131. printf(" rename:\n");
  132. printf(" - new_key: KEY1\n");
  133. printf(" old_key: KEY2 # transliterated with PREFIX added\n");
  134. printf(" - new_key: KEY3\n");
  135. printf(" old_key: KEY4 # transliterated with PREFIX added\n");
  136. printf(" # add as many as required\n");
  137. printf(" ```\n");
  138. printf("\n");
  139. printf("--------------------------------------------------------------------------------\n");
  140. printf(" INJECTING NEW KEYS\n");
  141. printf("\n");
  142. printf(" --inject KEY=VALUE\n");
  143. printf(" Inject constant fields to the output (both matched and unmatched logs).\n");
  144. printf(" --inject entries are added to unmatched lines too, when their key is\n");
  145. printf(" not used in --inject-unmatched (--inject-unmatched override --inject).\n");
  146. printf(" VALUE can use variable like ${OTHER_KEY} to be replaced with the values\n");
  147. printf(" of other keys available.\n");
  148. printf("\n");
  149. printf(" Up to %d fields can be injected.\n", MAX_INJECTIONS);
  150. printf("\n");
  151. printf(" In a YAML file:\n");
  152. printf(" ```yaml\n");
  153. printf(" inject:\n");
  154. printf(" - key: KEY1\n");
  155. printf(" value: 'VALUE1'\n");
  156. printf(" - key: KEY2\n");
  157. printf(" value: '${KEY3}${KEY4}' # gets the values of KEY3 and KEY4\n");
  158. printf(" # add as many as required\n");
  159. printf(" ```\n");
  160. printf("\n");
  161. printf("--------------------------------------------------------------------------------\n");
  162. printf(" REWRITING KEY VALUES\n");
  163. printf("\n");
  164. printf(" --rewrite KEY=/MATCH/REPLACE[/OPTIONS]\n");
  165. printf(" Apply a rewrite rule to the values of a specific key.\n");
  166. printf(" The first character after KEY= is the separator, which should also\n");
  167. printf(" be used between the MATCH, REPLACE and OPTIONS.\n");
  168. printf("\n");
  169. printf(" OPTIONS can be a comma separated list of `non-empty`, `dont-stop` and\n");
  170. printf(" `inject`.\n");
  171. printf("\n");
  172. printf(" When `non-empty` is given, MATCH is expected to be a variable\n");
  173. printf(" substitution using `${KEY1}${KEY2}`. Once the substitution is completed\n");
  174. printf(" the rule is matching the KEY only if the result is not empty.\n");
  175. printf(" When `non-empty` is not set, the MATCH string is expected to be a PCRE2\n");
  176. printf(" regular expression to be checked against the KEY value. This PCRE2\n");
  177. printf(" pattern may include named groups to extract parts of the KEY's value.\n");
  178. printf("\n");
  179. printf(" REPLACE supports variable substitution like `${variable}` against MATCH\n");
  180. printf(" named groups (when MATCH is a PCRE2 pattern) and `${KEY}` against the\n");
  181. printf(" keys defined so far.\n");
  182. printf("\n");
  183. printf(" Example:\n");
  184. printf(" --rewrite DATE=/^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/\n");
  185. printf(" ${day}/${month}/${year}\n");
  186. printf(" The above will rewrite dates in the format YYYY-MM-DD to DD/MM/YYYY.\n");
  187. printf("\n");
  188. printf(" Only one rewrite rule is applied per key; the sequence of rewrites for a\n");
  189. printf(" given key, stops once a rule matches it. This allows providing a sequence\n");
  190. printf(" of independent rewriting rules for the same key, matching the different\n");
  191. printf(" values the key may get, and also provide a catch-all rewrite rule at the\n");
  192. printf(" end, for setting the key value if no other rule matched it. The rewrite\n");
  193. printf(" rule can allow processing more rewrite rules when OPTIONS includes\n");
  194. printf(" the keyword 'dont-stop'.\n");
  195. printf("\n");
  196. printf(" Up to %d rewriting rules are allowed.\n", MAX_REWRITES);
  197. printf("\n");
  198. printf(" In a YAML file:\n");
  199. printf(" ```yaml\n");
  200. printf(" rewrite:\n");
  201. printf(" # the order if these rules in important - processed top to bottom\n");
  202. printf(" - key: KEY1\n");
  203. printf(" match: 'PCRE2 PATTERN WITH NAMED GROUPS'\n");
  204. printf(" value: 'all match fields and input keys as ${VARIABLE}'\n");
  205. printf(" inject: BOOLEAN # yes = inject the field, don't just rewrite it\n");
  206. printf(" stop: BOOLEAN # no = continue processing, don't stop if matched\n");
  207. printf(" - key: KEY2\n");
  208. printf(" non_empty: '${KEY3}${KEY4}' # match only if this evaluates to non empty\n");
  209. printf(" value: 'all input keys as ${VARIABLE}'\n");
  210. printf(" inject: BOOLEAN # yes = inject the field, don't just rewrite it\n");
  211. printf(" stop: BOOLEAN # no = continue processing, don't stop if matched\n");
  212. printf(" # add as many rewrites as required\n");
  213. printf(" ```\n");
  214. printf("\n");
  215. printf(" By default rewrite rules are applied only on fields already defined.\n");
  216. printf(" This allows shipping YAML files that include more rewrites than are\n");
  217. printf(" required for a specific input file.\n");
  218. printf(" Rewrite rules however allow injecting new fields when OPTIONS include\n");
  219. printf(" the keyword `inject` or in YAML `inject: yes` is given.\n");
  220. printf("\n");
  221. printf(" MATCH on the command line can be empty to define an unconditional rule.\n");
  222. printf(" Similarly, `match` and `non_empty` can be omitted in the YAML file.");
  223. printf("\n");
  224. printf("--------------------------------------------------------------------------------\n");
  225. printf(" UNMATCHED LINES\n");
  226. printf("\n");
  227. printf(" --unmatched-key KEY\n");
  228. printf(" Include unmatched log entries in the output with KEY as the field name.\n");
  229. printf(" Use this to include unmatched entries to the output stream.\n");
  230. printf(" Usually it should be set to --unmatched-key=MESSAGE so that the\n");
  231. printf(" unmatched entry will appear as the log message in the journals.\n");
  232. printf(" Use --inject-unmatched to inject additional fields to unmatched lines.\n");
  233. printf("\n");
  234. printf(" In a YAML file:\n");
  235. printf(" ```yaml\n");
  236. printf(" unmatched:\n");
  237. printf(" key: MESSAGE # inject the error log as MESSAGE\n");
  238. printf(" ```\n");
  239. printf("\n");
  240. printf(" --inject-unmatched LINE\n");
  241. printf(" Inject lines into the output for each unmatched log entry.\n");
  242. printf(" Usually, --inject-unmatched=PRIORITY=3 is needed to mark the unmatched\n");
  243. printf(" lines as errors, so that they can easily be spotted in the journals.\n");
  244. printf("\n");
  245. printf(" Up to %d such lines can be injected.\n", MAX_INJECTIONS);
  246. printf("\n");
  247. printf(" In a YAML file:\n");
  248. printf(" ```yaml\n");
  249. printf(" unmatched:\n");
  250. printf(" key: MESSAGE # inject the error log as MESSAGE\n");
  251. printf(" inject::\n");
  252. printf(" - key: KEY1\n");
  253. printf(" value: 'VALUE1'\n");
  254. printf(" # add as many constants as required\n");
  255. printf(" ```\n");
  256. printf("\n");
  257. printf("--------------------------------------------------------------------------------\n");
  258. printf(" FILTERING\n");
  259. printf("\n");
  260. printf(" --include PATTERN\n");
  261. printf(" Include only keys matching the PCRE2 PATTERN.\n");
  262. printf(" Useful when parsing JSON of logfmt logs, to include only the keys given.\n");
  263. printf(" The keys are matched after the PREFIX has been added to them.\n");
  264. printf("\n");
  265. printf(" --exclude PATTERN\n");
  266. printf(" Exclude the keys matching the PCRE2 PATTERN.\n");
  267. printf(" Useful when parsing JSON of logfmt logs, to exclude some of the keys given.\n");
  268. printf(" The keys are matched after the PREFIX has been added to them.\n");
  269. printf("\n");
  270. printf(" When both include and exclude patterns are set and both match a key,\n");
  271. printf(" exclude wins and the key will not be added, like a pipeline, we first\n");
  272. printf(" include it and then exclude it.\n");
  273. printf("\n");
  274. printf(" In a YAML file:\n");
  275. printf(" ```yaml\n");
  276. printf(" filter:\n");
  277. printf(" include: 'PCRE2 PATTERN MATCHING KEY NAMES TO INCLUDE'\n");
  278. printf(" exclude: 'PCRE2 PATTERN MATCHING KEY NAMES TO EXCLUDE'\n");
  279. printf(" ```\n");
  280. printf("\n");
  281. printf("--------------------------------------------------------------------------------\n");
  282. printf(" OTHER\n");
  283. printf("\n");
  284. printf(" -h, or --help\n");
  285. printf(" Display this help and exit.\n");
  286. printf("\n");
  287. printf(" --show-config\n");
  288. printf(" Show the configuration in YAML format before starting the job.\n");
  289. printf(" This is also an easy way to convert command line parameters to yaml.\n");
  290. printf("\n");
  291. printf("The program accepts all parameters as both --option=value and --option value.\n");
  292. printf("\n");
  293. printf("The maximum log line length accepted is %d characters.\n", MAX_LINE_LENGTH);
  294. printf("\n");
  295. printf("PIPELINE AND SEQUENCE OF PROCESSING\n");
  296. printf("\n");
  297. printf("This is a simple diagram of the pipeline taking place:\n");
  298. printf(" \n");
  299. printf(" +---------------------------------------------------+ \n");
  300. printf(" | INPUT | \n");
  301. printf(" | read one log line at a time | \n");
  302. printf(" +---------------------------------------------------+ \n");
  303. printf(" v v v v v v \n");
  304. printf(" +---------------------------------------------------+ \n");
  305. printf(" | EXTRACT FIELDS AND VALUES | \n");
  306. printf(" | JSON, logfmt, or pattern based | \n");
  307. printf(" | (apply optional PREFIX - all keys use capitals) | \n");
  308. printf(" +---------------------------------------------------+ \n");
  309. printf(" v v v v v v \n");
  310. printf(" +---------------------------------------------------+ \n");
  311. printf(" | RENAME FIELDS | \n");
  312. printf(" | change the names of the fields | \n");
  313. printf(" +---------------------------------------------------+ \n");
  314. printf(" v v v v v v \n");
  315. printf(" +---------------------------------------------------+ \n");
  316. printf(" | INJECT NEW FIELDS | \n");
  317. printf(" | constants, or other field values as variables | \n");
  318. printf(" +---------------------------------------------------+ \n");
  319. printf(" v v v v v v \n");
  320. printf(" +---------------------------------------------------+ \n");
  321. printf(" | REWRITE FIELD VALUES | \n");
  322. printf(" | pipeline multiple rewriting rules to alter | \n");
  323. printf(" | the values of the fields | \n");
  324. printf(" +---------------------------------------------------+ \n");
  325. printf(" v v v v v v \n");
  326. printf(" +---------------------------------------------------+ \n");
  327. printf(" | FILTER FIELDS | \n");
  328. printf(" | use include and exclude patterns on the field | \n");
  329. printf(" | names, to select which fields are sent to journal | \n");
  330. printf(" +---------------------------------------------------+ \n");
  331. printf(" v v v v v v \n");
  332. printf(" +---------------------------------------------------+ \n");
  333. printf(" | OUTPUT | \n");
  334. printf(" | generate Journal Export Format | \n");
  335. printf(" +---------------------------------------------------+ \n");
  336. printf(" \n");
  337. printf("--------------------------------------------------------------------------------\n");
  338. printf("JOURNAL FIELDS RULES (enforced by systemd-journald)\n");
  339. printf("\n");
  340. printf(" - field names can be up to 64 characters\n");
  341. printf(" - the only allowed field characters are A-Z, 0-9 and underscore\n");
  342. printf(" - the first character of fields cannot be a digit\n");
  343. printf(" - protected journal fields start with underscore:\n");
  344. printf(" * they are accepted by systemd-journal-remote\n");
  345. printf(" * they are NOT accepted by a local systemd-journald\n");
  346. printf("\n");
  347. printf(" For best results, always include these fields:\n");
  348. printf("\n");
  349. printf(" MESSAGE=TEXT\n");
  350. printf(" The MESSAGE is the body of the log entry.\n");
  351. printf(" This field is what we usually see in our logs.\n");
  352. printf("\n");
  353. printf(" PRIORITY=NUMBER\n");
  354. printf(" PRIORITY sets the severity of the log entry.\n");
  355. printf(" 0=emerg, 1=alert, 2=crit, 3=err, 4=warn, 5=notice, 6=info, 7=debug\n");
  356. printf(" - Emergency events (0) are usually broadcast to all terminals.\n");
  357. printf(" - Emergency, alert, critical, and error (0-3) are usually colored red.\n");
  358. printf(" - Warning (4) entries are usually colored yellow.\n");
  359. printf(" - Notice (5) entries are usually bold or have a brighter white color.\n");
  360. printf(" - Info (6) entries are the default.\n");
  361. printf(" - Debug (7) entries are usually grayed or dimmed.\n");
  362. printf("\n");
  363. printf(" SYSLOG_IDENTIFIER=NAME\n");
  364. printf(" SYSLOG_IDENTIFIER sets the name of application.\n");
  365. printf(" Use something descriptive, like: SYSLOG_IDENTIFIER=nginx-logs\n");
  366. printf("\n");
  367. printf("You can find the most common fields at 'man systemd.journal-fields'.\n");
  368. printf("\n");
  369. }