-
Notifications
You must be signed in to change notification settings - Fork 1
/
trap_error_info.sh
106 lines (94 loc) · 3.95 KB
/
trap_error_info.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/bash
#
# a common lib to show trapped error info.
#
# provide function `trap_error_info::register_show_error_info_handler` to register
# the error-trap handler which show error info when trapped error.
#
# by default, auto call `trap_error_info::register_show_error_info_handler` when source this script;
# disable by define `TRAP_ERROR_NO_AUTO_REGISTER` var
#
################################################################################
# api functions:
# - trap_error_info::register_show_error_info_handler
# - trap_error_info::get_stack_trace
################################################################################
#
#_ source guard begin _#
[ -n "${source_guard_84949D19_1C7A_40AF_BC28_BA5967A0B6CE:+has_value}" ] && return
source_guard_84949D19_1C7A_40AF_BC28_BA5967A0B6CE=$(realpath -- "${BASH_SOURCE[0]}")
# the value of source guard is the canonical dir path of this script
readonly source_guard_84949D19_1C7A_40AF_BC28_BA5967A0B6CE=${source_guard_84949D19_1C7A_40AF_BC28_BA5967A0B6CE%/*}
#_ source guard end _#
set -eEu -o pipefail -o functrace
# show stack trace.
#
# usage:
# trap_error_info::get_stack_trace <indentation> <hide level>
#
# - indentation default is empty("").
# - hide level default is 0.
# level 0 means show from the caller level stack trace.
#
# the format of stack trace:
# <func name>(<source file>:<line no>)
# example:
# foo_function(bar.sh:42)
#
trap_error_info::get_stack_trace() {
local indentation="${1:-}" hide_level="${2:-0}"
local func_stack_size="${#FUNCNAME[@]}"
TRAP_ERROR_INFO_STACK_TRACE=
local i stack_trace=
for ((i = hide_level + 1; i < func_stack_size; i++)); do
[ -n "${stack_trace:-}" ] && printf -v stack_trace '%s\n' "$stack_trace"
printf -v stack_trace '%s%s%s(%s:%s)' "$stack_trace" \
"$indentation" "${FUNCNAME[i]}" "${BASH_SOURCE[i]}" "${BASH_LINENO[i - 1]}"
done
TRAP_ERROR_INFO_STACK_TRACE="$stack_trace"
}
# official document of `Bash Variables`, e.g.
# BASH_SOURCE
# BASH_LINENO
# LINENO
# BASH_COMMAND
# https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
#
#
# related info:
#
# https://stackoverflow.com/questions/6928946/mysterious-lineno-in-bash-trap-err
# https://stackoverflow.com/questions/64786/error-handling-in-bash
# https://stackoverflow.com/questions/24398691/how-to-get-the-real-line-number-of-a-failing-bash-command
# https://unix.stackexchange.com/questions/39623/trap-err-and-echoing-the-error-line
# https://unix.stackexchange.com/questions/462156/how-do-i-find-the-line-number-in-bash-when-an-error-occured
# https://unix.stackexchange.com/questions/365113/how-to-avoid-error-message-during-the-execution-of-a-bash-script
# https://shapeshed.com/unix-exit-codes/#how-to-suppress-exit-statuses
# https://stackoverflow.com/questions/30078281/raise-error-in-a-bash-script/50265513#50265513
#
trap_error_info::_show_trapped_error_info() {
local exit_code="$1" error_command_line="$2"
echo '================================================================================'
echo "Trapped error!"
echo
echo "Exit status code: $exit_code"
echo "Stack trace:"
# set hide level 1, hide `trap_error_info::_show_trapped_error_info` self stack trace
trap_error_info::get_stack_trace ' ' 1
echo "$TRAP_ERROR_INFO_STACK_TRACE"
echo "Error code line:"
echo " $error_command_line"
echo '================================================================================'
} >&2
trap_error_info::register_show_error_info_handler() {
trap 'trap_error_info::_show_trapped_error_info $? "$BASH_COMMAND"' ERR
}
################################################################################
# auto run logic when source
#
# auto call `trap_error_info::register_show_error_info_handler` when source this script;
# disable by define `TRAP_ERROR_NO_AUTO_REGISTER` var
################################################################################
if [ -z "${TRAP_ERROR_NO_AUTO_REGISTER+defined}" ]; then
trap_error_info::register_show_error_info_handler
fi