Using The Command Line Interface (CLI)

As soon as you download AppView, you can start using the CLI to explore and gain insight into application behavior. No installation or configuration is required.

The CLI provides a rich set of capabilities for capturing and managing data from single applications. Data is captured in the local filesystem by default, and you can specify a different destination.

By default, the AppView CLI redacts binary data from console output. Although in most situations, the default behaviors of the AppView CLI and library are the same, they differ for binary data: it's omitted in the CLI, and allowed when using the library. To change this, use the allowbinary=true flag. The equivalent environment variable is APPVIEW_ALLOW_BINARY_CONSOLE. In the config file, allowbinary is an attribute of the console watch type for events.

To learn more, see the CLI Reference, and/or run appview --help or appview -h. And check out the Further Examples, which include both CLI and library use cases.

CLI Basics

The basic AppView CLI command is appview. The following examples progress from simple to more involved. Scoping a running process gets its own section. The final section explains how to appview an app that generates a large data set, and then explore that data.

View a New Process

Try scoping some well-known Linux commands, and view the results:

appview top
appview ls -al
appview curl https://www.google.com

When scoping browsers, we use the --no-sandbox option because virtually all modern browsers incorporate the sandbox security mechanism, and some sandbox implementations can interact with AppView in ways that cause the browser to hang, or not to start.

appview firefox --no-sandbox

View a Series of Shell Commands

In the shell that you open in this example, every command you run will be viewed:

appview bash

To release a process like appview bash above, exit the process in the shell. If you do this with the bash shell itself, you won't be able to appview bash again in the same terminal session.

AppView Cribl Stream

See what AppView shows Cribl Stream doing:

appview $CRIBL_HOME/bin/cribl server

You can take the idea of using AppView to reveal application behavior much further.

Use a Custom HTTP Header to Mark Your Data

When scoping apps that make HTTP requests, you can add the X-Appappview header, setting its content to the string of your choice.

Here's a trivial example of how this feature might be useful:

Suppose you want to appview HTTP requests to a weather forecast service, looking at many different cities, but labeling the data by country.

You could use the X-Appappview header to do your labeling:

appview curl --header "X-Appappview: Canada" wttr.in/calgary
appview curl --header "X-Appappview: Canada" wttr.in/ottawa
...

appview curl --header "X-Appappview: Brazil" wttr.in/recife
appview curl --header "X-Appappview: Brazil" wttr.in/riodejaneiro
...

In the resulting AppView events, the body > data element would include an "x-appview" field whose value would be the country named in the request's X-Appappview header.

Invoke a Config File While Scoping a New Process

Why create a custom configuration file? One popular reason is to change the destination to which AppView sends captured data to someplace other than the local filesystem (the default). To learn about the possibilities, read the comments in the default Configuration File.

This example appviews the echo command while invoking a configuration file named cloud.yml:

appview run -u cloud.yml -- echo foo

Scoping a Running Process

You attach AppView to a process using either a process ID or a process name.

Attaching by Process ID

In this example, we'll start by grepping for process IDs of cribl (Cribl Stream) processes:

$ ps -ef | grep cribl
ubuntu    1820     1  1 21:03 pts/4    00:00:02 /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl server
ubuntu    1838  1820  4 21:03 pts/4    00:00:07 /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl.js server -r CONFIG_HELPER
ubuntu    1925 30025  0 21:06 pts/3    00:00:00 grep --color=auto cribl

Then, we'll attach to a process of interest:

ubuntu@ip-127-0-0-1:~/someusername/appview3$ sudo appview attach 1820

Attaching by Process Name

In this example, we try to attach to a Cribl Stream process by its name, which will be cribl. Since there's more than one process, AppView lists them and prompts us to choose one:

$ sudo appview attach cribl
Found multiple processes matching that name...
ID  PID   USER    APPVIEWD  COMMAND
1   1820  ubuntu  false   /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl server
2   1838  ubuntu  false   /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl /home/ubuntu/someusername/cribl/4.0.3/m/cribl/bin/cribl.js server -r CONFIG_HELPER
Select an ID from the list:
2
WARNING: Session history will be stored in /home/ubuntu/.appview/history and owned by root
Attaching to process 1838

Detaching from Processes

You can also detach AppView from a process.

Furthermore, if you want to undo the effects of the appview attach, appview start, and/or appview service commands, run the appview stop command. This runs appview detach --all, removes the rules file from the system, and removes appview from service configurations.

When you detach from a process, AppView:

  • Stops emitting events and metrics for the process.
  • Closes relevant connections.
  • Removes its interpositions from the process' functions, and/or unhooks from the process' functions, as relevant.

What AppView does not do is unload its library.

More About Scoping Running Processes

To attach AppView to a running process:

  1. You must run appview as root, or with sudo.
  2. If you attach to a shell, AppView does not automatically appview its child processes.
  3. You can attach to a process that is executing within a container context by running appview attach inside that container or from the host.

When you attach AppView to a process, its child processes are not automatically viewed.

You cannot attach to a static executable's process.

No HTTP/1.1 events and headers are emitted when AppView attaches to a Go process that uses the azure-sdk-for-go package.

No events are emitted from files or sockets that exist before AppView attaches to a process.

  • AppView events will be produced only for file or socket descriptors opened after AppView is attached.

    • For example, suppose a process opens a socket descriptor before AppView is attached. Subsequent sends and receives on this socket will not produce AppView events.

Working with HTTP Payloads

When you appview an app that produces HTTP traffic, you can capture the payloads using the -p or --payloads option. This is AppView's payloads feature (see the payload section in the AppView config file), which is disabled by default, because it can create large amounts of data, and because it captures payloads unencrypted.

When the payloads feature is enabled, setting APPVIEW_PAYLOAD_TO_DISK to true guarantees that AppView will write payloads to the local directory specified in APPVIEW_PAYLOAD_DIR.

Exploring Captured Data

You can appview apps that generate large data sets, and then use AppView CLI subcommands and options to monitor and visualize the data. The following extended example introduces this technique.

Start by scoping the ps command:

appview run -- ps -ef

Show last session's captured metrics with appview metrics:

NAME             VALUE      TYPE     UNIT           PID     TAGS
proc.start       1          Count    process        5470    args: ps -ef,gid: 0,groupname: root,host: ip-10-8-107-15…
proc.cpu         60898      Count    microsecond    5470    host: my_hostname,proc: ps
proc.cpu_perc    0.60898    Gauge    percent        5470    host: my_hostname,proc: ps
proc.mem         67512      Gauge    kibibyte       5470    host: my_hostname,proc: ps
proc.thread      2          Gauge    thread         5470    host: my_hostname,proc: ps
proc.fd          6          Gauge    file           5470    host: my_hostname,proc: ps
proc.child       1          Gauge    process        5470    host: my_hostname,proc: ps
fs.read          379832     Count    byte           5470    host: my_hostname,proc: ps,summary: true
net.rx           401        Count    byte           5470    class: unix_tcp,host: my_hostname,proc: ps,summary: …
net.tx           361        Count    byte           5470    class: unix_tcp,host: my_hostname,proc: ps,summary: …
fs.seek          150        Count    operation      5470    host: my_hostname,proc: ps,summary: true
fs.stat          136        Count    operation      5470    host: my_hostname,proc: ps,summary: true
...

Plot a chart of last session's proc.cpu metric with appview metrics -m proc.cpu -g:

 80000 ┼                   ╭╮
 76000 ┤                   ││
 72000 ┤                   ││
 68000 ┤                   ││
 64000 ┤                   ││
 60000 ┤                   ││
 56000 ┤                   ││
 52000 ┤                   ││                                     ╭╮                               ╭╮   ╭─
 48000 ┤                   ││                                     ││                               ││   │
 44000 ┤                   ││                                     ││                               ││   │
 40000 ┤ ╭╮                ││                                     ││          ╭╮                ╭─╮││ ╭╮│
 36000 ┤ ││                ││                                     ││          ││                │ │││ │││
 32000 ┤ ││╭╮              ││          ╭╮    ╭╮ ╭╮                ││ ╭╮       ││ ╭╮ ╭╮ ╭╮ ╭╮ ╭╮╭╯ ╰╯╰╮│╰╯
 28000 ┤ ││││              ││          ││    ││ ││                ││ ││       ││ ││ ││ ││ ││ │││     ││
 24000 ┤ ││││              ││          ││    ││ ││                ││ ││       ││ ││ ││ ││ ││ │││     ││
 20000 ┤╭╯││╰╮ ╭╮╭╮ ╭──╮╭╮ ││ ╭╮ ╭╮ ╭╮ ││ ╭──╯│ ││╭─╮ ╭╮    ╭───╮ ││╭╯│ ╭╮ ╭╮ │╰╮││ ││ ││ ││ │╰╯     ╰╯
 16000 ┤│ ││ │ ││││ │  │││ ││ ││ ││ ││ ││ │   │ │││ │ ││    │   │ │││ │ ││ ││ │ │││ ││ ││ ││ │
 12000 ┤│ ╰╯ ╰─╯╰╯╰─╯  ╰╯│╭╯╰─╯╰─╯│╭╯╰─╯╰─╯   ╰─╯╰╯ ╰─╯╰────╯   │╭╯╰╯ │╭╯╰─╯╰─╯ ╰╯╰─╯│╭╯╰─╯╰─╯
  8000 ┤│                ││       ││                            ││    ││             ││
  4000 ┤│                ││       ││                            ││    ││             ││
     0 ┼╯                ╰╯       ╰╯                            ╰╯    ╰╯             ╰╯

Display the last session's captured events with appview events:

[EkA1] Jul 12 02:11:15 ps fs fs.open file:/proc/17721/stat
[OrA1] Jul 12 02:11:15 ps fs fs.close file:/proc/17721/stat file_read_bytes:158 file_read_ops:1 file_write_bytes:0 file_write_ops:0
[xAA1] Jul 12 02:11:15 ps fs fs.open file:/proc/17721/status
[LHA1] Jul 12 02:11:15 ps fs fs.close file:/proc/17721/status file_read_bytes:952 file_read_ops:1 file_write_bytes:0 file_write_ops:0
[vQA1] Jul 12 02:11:15 ps fs fs.open file:/proc/17721/cmdline
[IXA1] Jul 12 02:11:15 ps fs fs.close file:/proc/17721/cmdline file_read_bytes:0 file_read_ops:1 file_write_bytes:0 file_write_ops:0
[s6B1] Jul 12 02:11:15 ps fs fs.open file:/proc/17758/stat
...

Now view a command which produces HTTP and other kinds of events:

appview run -- curl https://www.google.com

Filter out everything but http from the last session's events, with appview events -t http:

[vL1] Jul 12 02:14:07 curl http http.req http_host:www.google.com http_method:GET http_scheme:https http_target:/
[PU1] Jul 12 02:14:08 curl http http.resp http_host:www.google.com http_method:GET http_target:/

View the history of the current AppView session with appview history:

Displaying last 20 sessions
ID  COMMAND CMDLINE                     PID     AGE     DURATION    TOTAL EVENTS
4   ps      ps -ef                      5464    3m6s    12ms        788
5   curl    curl https://www.google.…   5492    14s     141ms       20

AppView another command which will produce a variety of events ...

# appview run -- apt update
Hit:1 http://us-west-2.ec2.archive.ubuntu.com/ubuntu bionic InRelease
Get:2 http://us-west-2.ec2.archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]                                      
Get:3 http://us-west-2.ec2.archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]                                    
Hit:4 https://download.docker.com/linux/ubuntu bionic InRelease                                                                                
Get:5 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]                                                                    
Hit:6 https://baltocdn.com/helm/stable/debian all InRelease
...

... Then, show only the last 10 events of sourcetype console, sorted in ascending order by timestamp:

# appview events --sort _time --sourcetype console --last 10 --reverse
[g2Wg] Jul 12 02:14:49 apt console stdout message:"                                  0% [Working] 0% [16 Packages store 0 B]                …"
[zvUe] Jul 12 02:14:49 apt console stdout message:"                                  0% [Working] 0% [16 Packages store 0 B]                …"
[ucRe] Jul 12 02:14:50 find console stdout message:/var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_universe_binary-amd6…
[zkRe] Jul 12 02:14:50 dirname console stdout message:/var/lib/update-notifier
[I0Se] Jul 12 02:14:50 mktemp console stdout message:/var/lib/update-notifier/tmp.ut1sgTEuvb
[gmUg] Jul 12 02:14:54 python3 console stdout message:"39 updates can be applied immediately. To see these additional updates run: apt list …"
[gZ7h] Jul 12 02:14:54 apt console stdout message:"Reading package lists... 0%"
[1a2i] Jul 12 02:14:54 apt console stdout message:"Reading package lists... 0%  Reading package lists... 0%  Reading package lists... 3%  Re…"
[cp1i] Jul 12 02:14:54 apt console stdout message:"Reading package lists... 0%  Reading package lists... 0%  Reading package lists... 3%  Re…"
[QU2i] Jul 12 02:14:56 apt console stderr message:"W: An error occurred during the signature verification. The repository is not updated and…"

View a command which reads and writes over the network:

# appview curl wttr.in    
Weather report: Portland, Oregon, United States

      \   /     Sunny
       .-.      93 °F          
    ― (   ) ―   ↓ 6 mph        
       `-’      9 mi           
      /   \     0.0 in         
                                                       ┌─────────────┐                                                       
┌──────────────────────────────┬───────────────────────┤  Mon 11 Jul ├───────────────────────┬──────────────────────────────┐
│            Morning           │             Noon      └──────┬──────┘     Evening           │             Night            │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│     \   /     Sunny          │     \   /     Sunny          │     \   /     Sunny          │     \   /     Clear          │
│      .-.      68 °F          │      .-.      89 °F          │      .-.      +95(93) °F     │      .-.      78 °F          │
│   ― (   ) ―   ↓ 5-6 mph      │   ― (   ) ―   ↘ 6-7 mph      │   ― (   ) ―   ↘ 10-11 mph    │   ― (   ) ―   ↘ 8-15 mph     │
│      `-’      6 mi           │      `-’      6 mi           │      `-’      6 mi           │      `-’      6 mi           │
│     /   \     0.0 in | 0%    │     /   \     0.0 in | 0%    │     /   \     0.0 in | 0%    │     /   \     0.0 in | 0%    │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘       
...

Then, show only events containing the string net_bytes, and display the fields net_bytes_sent and net_bytes_recv, with their values:

# appview events --fields net_bytes_sent,net_bytes_recv --match net_bytes
[e91] Jul 12 02:15:41 curl net net.close net_bytes_sent:71 net_bytes_recv:8773