Line data Source code
1 : /*
2 : * Copyright (C) 2021 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 9 : import cockpit from "cockpit";
6 : import { journal } from "journal";
7 :
8 : // Sometimes `journalctl` can be compiled without `PCRE2` which means
9 : // that `--grep` is not usable. Hide the search box in such cases.
10 9 : export function checkJournalctlGrep(setShowTextSearch) {
11 9 : cockpit.spawn(["journalctl", "--version"])
12 9 : .then(m => {
13 1 : if (m.indexOf("-PCRE2") !== -1) {
14 1 : setShowTextSearch(false);
15 1 : } else {
16 9 : setShowTextSearch(true);
17 9 : }
18 9 : });
19 9 : }
20 :
21 : // Build the journalctl query for the inline help popover
22 9 : export const getFilteredQuery = ({ match, options }) => {
23 9 : const cmd = journal.build_cmd(match, options);
24 9 : const filtered_cmd = cmd.filter(i => i !== "-q" && i !== "--output=json");
25 9 : if (filtered_cmd[filtered_cmd.length - 1] == "--")
26 8 : filtered_cmd.pop();
27 :
28 9 : return filtered_cmd.join(" ");
29 9 : };
30 :
31 9 : export const getGrepFiltersFromOptions = ({ options }) => {
32 9 : const grep = options.grep || "";
33 9 : let full_grep = "";
34 9 : const match = [];
35 :
36 : // `prio` is a legacy name. Accept it, but don't generate it
37 6 : const prio_level = options.priority || options.prio || "err";
38 9 : full_grep += "priority:" + prio_level + " ";
39 :
40 3 : if (options.service) {
41 2 : options.service.split(",").forEach(s => {
42 2 : if (!s.endsWith(".service"))
43 1 : s = s + ".service";
44 2 : match.push('_SYSTEMD_UNIT=' + s, "+", "COREDUMP_UNIT=" + s, "+", "UNIT=" + s);
45 2 : });
46 3 : full_grep += "service:" + options.service + " ";
47 1 : } else if (options["user-service"]) {
48 1 : options["user-service"].split(",").forEach(s => {
49 1 : if (!s.endsWith(".service"))
50 0 : s = s + ".service";
51 1 : match.push('_SYSTEMD_USER_UNIT=' + s, "+", "COREDUMP_USER_UNIT=" + s, "+", "USER_UNIT=" + s);
52 1 : });
53 2 : full_grep += "user-service:" + options["user-service"] + " ";
54 2 : }
55 :
56 6 : if (options.tag && options.tag !== "*") {
57 6 : match.push('SYSLOG_IDENTIFIER=' + options.tag);
58 6 : full_grep += "identifier:" + options.tag + " ";
59 6 : }
60 :
61 9 : if (options.boot)
62 2 : full_grep += "boot:" + options.boot + " ";
63 :
64 9 : if (options.since)
65 7 : full_grep += "since:" + options.since.replaceAll(" ", "\\ ") + " ";
66 :
67 9 : if (options.until)
68 3 : full_grep += "until:" + options.until.replaceAll(" ", "\\ ") + " ";
69 :
70 : // Other filters may be passed as well
71 9 : Object.keys(options).forEach(k => {
72 2 : if (k === k.toUpperCase() && options[k]) {
73 1 : options[k].split(",").forEach(v => match.push(k + "=" + v));
74 2 : full_grep += k + '=' + options[k] + " ";
75 2 : }
76 9 : });
77 :
78 9 : full_grep += grep;
79 :
80 9 : return [full_grep, match];
81 9 : };
82 :
83 2 : const split_search = (text) => {
84 2 : let last_i = 0;
85 2 : const words = [];
86 :
87 : // Add space so the following loop can always pick group on space (without trailing
88 : // space the last group would not be recognized and it would need a special check)
89 2 : if (text.length && text[text.length - 1] !== " ")
90 2 : text += " ";
91 :
92 2 : for (let i = 1; i < text.length; i++) {
93 2 : if (text[i] === " " && text[i - 1] !== "\\") {
94 2 : words.push(text.substring(last_i, i).replaceAll("\\ ", " "));
95 2 : last_i = i + 1;
96 2 : }
97 2 : }
98 2 : return words;
99 2 : };
100 :
101 2 : export const getOptionsFromTextInput = (value) => {
102 2 : const new_items = {};
103 2 : const values = split_search(value)
104 2 : .filter(item => {
105 2 : let s = item.split("=");
106 1 : if (s.length === 2 && s[0] === s[0].toUpperCase()) {
107 1 : new_items[s[0]] = s[1];
108 1 : return false;
109 1 : }
110 :
111 2 : const well_know_keys = ["since", "until", "boot", "priority", "follow", "service", "identifier"];
112 2 : const map_keys = (key) => {
113 2 : if (key === "identifier")
114 2 : return "tag";
115 2 : if (key == "service")
116 0 : return "unit";
117 2 : return key;
118 2 : };
119 2 : s = item.split(/:(.*)/);
120 2 : if (s.length >= 2 && well_know_keys.includes(s[0])) {
121 2 : new_items[map_keys(s[0])] = s[1];
122 2 : return false;
123 2 : }
124 :
125 1 : return true;
126 2 : });
127 2 : new_items.grep = values.join(" ");
128 2 : return new_items;
129 2 : };
|