# How to specify you own custom shell instructions

Prerequisites:

* [Installation how-to](./install_update_remove_how_to.md#how-to-install).
* [Firewall how-to for SSH](./firewall_how_to.md#firewall-configuration-for-ssh).
* [Firewall how-to for EPICS](./firewall_how_to.md#standard-firewall-configuration-for-epics).
* [`.cmd` and `.substitutions` how-to](./cmd_and_sub_how_to.md)
* [Security how-to](./security_how_to.md)

In order to specify you own custom {{shell_instruction}}s, here are the steps to follow:

1. Find what you want to monitor. E.g. let's pretend you want to monitor the following metrics:

    * Cumulated CPU usage (over all CPU cores) of Firefox.
    * Cumulated CPU usage (over all CPU cores) of Java.
    * Cumulated CPU usage (over all CPU cores) of CSS (Control System Studio).
    * Error message in `/path/to/file.log`.
    * Error message in `/path/to/another-file.log`.

2. Find out what {{shell_instruction}} you want to use in order to retrieve the wanted data for each thing
   to monitor. E.g.:

    * Cumulated CPU usage (over all CPU cores) of Firefox:

        ```{code} bash
        ps -eo %cpu,args | grep firefox | awk '{print $1}' | paste -sd+ - | bc
        ```

    * Cumulated CPU usage (over all CPU cores) of Java:

        ```{code} bash
        ps -eo %cpu,args | grep java | awk '{print $1}' | paste -sd+ - | bc
        ```

    * Cumulated CPU usage (over all CPU cores) of CSS (Control System Studio):

        ```{code} bash
        ps -eo %cpu,args | grep css | awk '{print $1}' | paste -sd+ - | bc
        ```

    * Error message in `/path/to/file.log`:

        ```{code} bash
        cat /path/to/file.log | grep -i 'error'
        ```

    * Error message in `/path/to/another-file.log`.

        ```{code} bash
        cat /path/to/another-file.log | grep -i 'error'
        ```

3. On the {{target}}, make sure that the needed packages have been white-listed
   like described in
   the [security how-to](./security_how_to.md#how-to-setup-a-customized-restricted-shell).
   I.e., in this example the needed packages are
   `ps`, `grep`, `awk`, `paste`, `bc` and `cat`,
   so after following carefully
   the [security how-to](./security_how_to.md#how-to-setup-a-customized-restricted-shell)
   instructions, here is how to white-list the needed packages:

    ```{code} bash
    target $ sudo ln -s /bin/ps /home/sshmonitor-user/bin
    target $ sudo ln -s /bin/grep /home/sshmonitor-user/bin
    target $ sudo ln -s /bin/awk /home/sshmonitor-user/bin
    target $ sudo ln -s /bin/paste /home/sshmonitor-user/bin
    target $ sudo ln -s /bin/bc /home/sshmonitor-user/bin
    target $ sudo ln -s /bin/cat /home/sshmonitor-user/bin
    ```

4. Create a {{substitutions}} file in order to specify the {{shell_instruction}}s.
   E.g. in this example, you might want a substitution file that looks like the one bellow:

    ```{code} bash
    $ vi myTargetMonitoringTop/iocBoot/iocMyTargetMonitoring/custom_monitoring.substitutions

        > global
        > {
        >     PREFIX = "${PREFIX_MACRO}"
        >     SSH_OPTS_AND_ARGS = "${SSH_OPTS_AND_ARGS_MACRO}"
        > }
        >
        > file "${TOP}/db/ssh_monitor_core.template"
        > {
        >     {
        >         CATEGORY = "custom:"
        >
        >         # scalar shell instruction 1 used to extract CPU usage of Firefox
        >         # the result of this shell instruction is stored in the record called "${PREFIX}${CATEGORY}${PV_NAME_SCALAR_1}"
        >         PV_NAME_SCALAR_1 = "cpu_usage_firefox"
        >         SCALAR_1_INSTRUCTION = "ps -eo %cpu,args | grep firefox | awk '{print $1}' | paste -sd+ - | bc"
        >         LOAD_SCALAR_1 = ""
        >
        >         # scalar shell instruction 2 used to extract CPU usage of Java
        >         # (the result of this shell instruction is stored in the record called "${PREFIX}${CATEGORY}${PV_NAME_SCALAR_2}"
        >         PV_NAME_SCALAR_2 = "cpu_usage_java"
        >         SCALAR_2_INSTRUCTION = "ps -eo %cpu,args | grep java | awk '{print $1}' | paste -sd+ - | bc"
        >         LOAD_SCALAR_2 = ""
        >
        >         # scalar shell instruction 3 used to extract CPU usage of CSS (Control System Studio)
        >         # the result of this shell instruction is stored in the record called "${PREFIX}${CATEGORY}${PV_NAME_SCALAR_3}"
        >         PV_NAME_SCALAR_3 = "cpu_usage_css"
        >         SCALAR_3_INSTRUCTION = "ps -eo %cpu,args | grep css | awk '{print $1}' | paste -sd+ - | bc"
        >         LOAD_SCALAR_3 = ""
        >
        >         # string shell instruction 1 used to extract error message from /path/to/file.log
        >         # the result of this shell instruction is stored in the record called "${PREFIX}${CATEGORY}${PV_NAME_STRING_1}"
        >         PV_NAME_STRING_1 = "error_message_file_1"
        >         STRING_1_INSTRUCTION = "cat /path/to/file.log | grep -i 'error'"
        >         LOAD_STRING_1 = ""
        >
        >         # string shell instruction 2 used to extract error message from /path/to/another-file.log
        >         # the result of this shell instruction is stored in the record called "${PREFIX}${CATEGORY}${PV_NAME_STRING_2}"
        >         PV_NAME_STRING_2 = "error_message_file_2"
        >         STRING_2_INSTRUCTION = "cat /path/to/another-file.log | grep -i 'error'"
        >         LOAD_STRING_2 = ""
        >     }
        > }
    ```

5. Load your custom {{substitutions}} file in the {{cmd}} file (e.g. `st_target1.cmd`):

    ```{code} bash
    $ vi myTargetMonitoringTop/iocBoot/iocMyTargetMonitoring/st_target1.cmd

        > ...
      + > dbLoadTemplate("${TOP}/iocBoot/${IOC}/custom_monitoring.substitutions", "PREFIX_MACRO=${PREFIX}, SSH_OPTS_AND_ARGS_MACRO=${SSH_OPTS_AND_ARGS}")
        > ...
    ```

6. [Run SSH Monitor](./run_ssh_monitor_how_to.md) and make sure everything is working as intended.

```{seealso}
See [custom shell instructions explanations](../../explanations/custom_shell_instructions_explanations.md)
for more details.
```

