OILS / doc / xtrace.md View on Github | oilshell.org

143 lines, 109 significant
1---
2default_highlighter: oils-sh
3---
4
5Tracing Execution in Oils (`xtrace`)
6===================================
7
8Oils extends shell's `set -x` / `xtrace` mechanism to give you more visibility
9into your program's execution. It shows high-level program structure
10("functions", `eval`) as well as runtime events (starting and stopping external
11processes).
12
13<div id="toc">
14</div>
15
16## Background
17
18In shell, the `$PS4` variable controls the prefix of each trace line. The
19default value is `'+ '`, which results in traces like this:
20
21 $ sh -x -c 'echo 1; echo 2'
22 + echo 1
23 1
24 + echo 2
25 2
26
27### What's Wrong With `set -x`?
28
29- It shows only an `argv` array for commands. It doesn't tell you if the
30 command is a builtin, shell function, or external binary, which is important
31 for program comprehension (and performance).
32- It doesn't show you which commands are run in **which processes**. Because
33 processes have their own state, this is also crucial for understanding a
34 shell program. (Example: does `echo x | read` mutate a variable?)
35- It's **missing** other information, like when processes are started and
36 stopped, the exit status, and when commands come from `eval` or `source`.
37- Shell **concurrency** makes the trace incomprehensible. For example, partial
38 lines can be interleaved.
39- Most implementations don't show non-printable and whitespace characters in a
40 coherent way.
41
42<!-- TODO: you generally lose tracing across processes. -->
43
44## Oils Enhancements
45
46Oils solves these problems. Here's an example of tracing a builtin, a pipeline,
47then another builtin:
48
49 $ osh -O ysh:upgrade -x -c 'set +e; ls | grep OOPS | wc -l; echo end'
50 . builtin set '+e'
51 > pipeline
52 | part 103
53 . 103 exec ls
54 | part 104
55 . 104 exec grep OOPS
56 | command 105: wc -l
57 ; process 103: status 0
58 ; process 104: status 1
59 ; process 105: status 0
60 < pipeline
61 . builtin echo end
62
63- Builtins are shown with the `builtin` prefix.
64- External commands are shown with the `command` prefix.
65- Bare `exec()` calls are shown with the `exec` prefix.
66- It shows **synchronous** shell constructs with indentation and the `>`
67 and `<` characters. This includes the entire pipeline, as well as `proc`
68 calls (not shown).
69- It shows process starts and ends with the `|` and `;` characters. These are
70 **asynchronous** in general.
71- It shows the exit status of **every process**, which is important for
72 reasoning about failure.
73- It annotates trace lines with the shell PID (when it's not the root PID).
74- Strings in `argv` arrays may be quoted with [QSN]($oils-doc:qsn.html). This
75 shows special characters unambiguously, and ensures that each trace entry is
76 exactly one physical line.
77
78### Option Names
79
80This functionality is enabled by the
81[xtrace_rich][] option, but you should
82generally use the `ysh:upgrade` option group. This group turns on
83[xtrace_rich][] and turns off [xtrace_details][], which is equivalent to:
84
85 $ shopt --set xtrace_rich
86 $ shopt --unset xtrace_details
87
88[xtrace_rich]: ref/chap-option.html#ysh:upgrade
89[xtrace_details]: ref/chap-option.html#ysh:upgrade
90
91### Variables for the Trace Line
92
93In YSH, the default trace line prefix is:
94
95 $ PS4='${SHX_indent}${SHX_punct}${SHX_pid_str} '
96
97- `SHX_indent` is affected by synchronous constructs like `proc` and `eval`, as
98 well as new processes.
99- `SHX_pid_str` is only set for child shell processes (to avoid redundancy).
100 It has a space at the beginning like `' 123'`.
101
102`SHX_punct` is one of the following:
103
104- `+` for legacy shell tracing ([xtrace_details][])
105- `.` for `builtin` and `exec`
106- `>` and `<` for internal, stack-based, **synchronous** constructs
107 - `proc`, `eval`, and `source`, an entire pipeline, and the `wait` builtin
108 - running trap handlers (which happens in the main loop)
109- `|` and `;` for process start and wait
110 - **synchronous** processes: subshell aka [forkwait][], command sub
111 like `$(date)`, simple commands (`;`)
112 - **async** processes: [fork][] (`&`), pipeline parts, process subs
113 like `<(sort left.txt)`, the process that writes a here doc
114
115[forkwait]: ref/chap-builtin-cmd.html#forkwait
116[fork]: ref/chap-builtin-cmd.html#fork
117
118TODO: Cross-shell tracing
119
120- `SHX_descriptor` is alias for `BASH_XTRACEFD` ?
121- Inherited `$SHX_indent` and `$SHX_pid_str`
122
123## Other Useful Variables
124
125These variables can enhance the traces.
126
127- `@BASH_SOURCE`, `@BASH_LINENO`, `@FUNCNAME`, `$LINENO`
128 - TODO: Add `@SOURCE_NAMES` as alias? `LINE_NUMS`?
129- TODO: `$SECONDS` for timing
130
131<!--
132And OIL_PID? or maybe OIL_CURRENT_PID. or maybe getpid() is better -
133distinguish between functions and values
134-->
135
136## Parsing `xtrace_rich` Output
137
138TODO
139
140- It's concurrent, but lines are atomically written
141- Specify a regular language?
142- Coalesce by PID?
143