logging.sh 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/env bash
  2. # Copyright 2014 The Kubernetes Authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. # Controls verbosity of the script output and logging.
  16. KUBE_VERBOSE="${KUBE_VERBOSE:-5}"
  17. # Handler for when we exit automatically on an error.
  18. # Borrowed from https://gist.github.com/ahendrix/7030300
  19. kube::log::errexit() {
  20. local err="${PIPESTATUS[*]}"
  21. # If the shell we are in doesn't have errexit set (common in subshells) then
  22. # don't dump stacks.
  23. set +o | grep -qe "-o errexit" || return
  24. set +o xtrace
  25. local code="${1:-1}"
  26. # Print out the stack trace described by $function_stack
  27. if [ ${#FUNCNAME[@]} -gt 2 ]
  28. then
  29. kube::log::error "Call tree:"
  30. for ((i=1;i<${#FUNCNAME[@]}-1;i++))
  31. do
  32. kube::log::error " ${i}: ${BASH_SOURCE[${i}+1]}:${BASH_LINENO[${i}]} ${FUNCNAME[${i}]}(...)"
  33. done
  34. fi
  35. kube::log::error_exit "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}. '${BASH_COMMAND}' exited with status ${err}" "${1:-1}" 1
  36. }
  37. kube::log::install_errexit() {
  38. # trap ERR to provide an error handler whenever a command exits nonzero this
  39. # is a more verbose version of set -o errexit
  40. trap 'kube::log::errexit' ERR
  41. # setting errtrace allows our ERR trap handler to be propagated to functions,
  42. # expansions and subshells
  43. set -o errtrace
  44. }
  45. # Print out the stack trace
  46. #
  47. # Args:
  48. # $1 The number of stack frames to skip when printing.
  49. kube::log::stack() {
  50. local stack_skip=${1:-0}
  51. stack_skip=$((stack_skip + 1))
  52. if [[ ${#FUNCNAME[@]} -gt ${stack_skip} ]]; then
  53. echo "Call stack:" >&2
  54. local i
  55. for ((i=1 ; i <= ${#FUNCNAME[@]} - stack_skip ; i++))
  56. do
  57. local frame_no=$((i - 1 + stack_skip))
  58. local source_file=${BASH_SOURCE[${frame_no}]}
  59. local source_lineno=${BASH_LINENO[$((frame_no - 1))]}
  60. local funcname=${FUNCNAME[${frame_no}]}
  61. echo " ${i}: ${source_file}:${source_lineno} ${funcname}(...)" >&2
  62. done
  63. fi
  64. }
  65. # Log an error and exit.
  66. # Args:
  67. # $1 Message to log with the error
  68. # $2 The error code to return
  69. # $3 The number of stack frames to skip when printing.
  70. kube::log::error_exit() {
  71. local message="${1:-}"
  72. local code="${2:-1}"
  73. local stack_skip="${3:-0}"
  74. stack_skip=$((stack_skip + 1))
  75. if [[ ${KUBE_VERBOSE} -ge 4 ]]; then
  76. local source_file=${BASH_SOURCE[${stack_skip}]}
  77. local source_line=${BASH_LINENO[$((stack_skip - 1))]}
  78. echo "!!! Error in ${source_file}:${source_line}" >&2
  79. [[ -z ${1-} ]] || {
  80. echo " ${1}" >&2
  81. }
  82. kube::log::stack ${stack_skip}
  83. echo "Exiting with status ${code}" >&2
  84. fi
  85. exit "${code}"
  86. }
  87. # Log an error but keep going. Don't dump the stack or exit.
  88. kube::log::error() {
  89. timestamp=$(date +"[%m%d %H:%M:%S]")
  90. echo "!!! ${timestamp} ${1-}" >&2
  91. shift
  92. for message; do
  93. echo " ${message}" >&2
  94. done
  95. }
  96. # Print an usage message to stderr. The arguments are printed directly.
  97. kube::log::usage() {
  98. echo >&2
  99. local message
  100. for message; do
  101. echo "${message}" >&2
  102. done
  103. echo >&2
  104. }
  105. kube::log::usage_from_stdin() {
  106. local messages=()
  107. while read -r line; do
  108. messages+=("${line}")
  109. done
  110. kube::log::usage "${messages[@]}"
  111. }
  112. # Print out some info that isn't a top level status line
  113. kube::log::info() {
  114. local V="${V:-0}"
  115. if [[ ${KUBE_VERBOSE} < ${V} ]]; then
  116. return
  117. fi
  118. for message; do
  119. echo "${message}"
  120. done
  121. }
  122. # Just like kube::log::info, but no \n, so you can make a progress bar
  123. kube::log::progress() {
  124. for message; do
  125. echo -e -n "${message}"
  126. done
  127. }
  128. kube::log::info_from_stdin() {
  129. local messages=()
  130. while read -r line; do
  131. messages+=("${line}")
  132. done
  133. kube::log::info "${messages[@]}"
  134. }
  135. # Print a status line. Formatted to show up in a stream of output.
  136. kube::log::status() {
  137. local V="${V:-0}"
  138. if [[ ${KUBE_VERBOSE} < ${V} ]]; then
  139. return
  140. fi
  141. timestamp=$(date +"[%m%d %H:%M:%S]")
  142. echo "+++ ${timestamp} ${1}"
  143. shift
  144. for message; do
  145. echo " ${message}"
  146. done
  147. }