LCOV - code coverage report
Current view: top level - pkg/systemd - logsHelpers.js Coverage Total Hit
Test: cockpit Lines: 98.0 % 98 96
Test Date: 2026-07-02 14:11:36

            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 : };
        

Generated by: LCOV version 2.0-1