runtime.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package runtime
  14. import (
  15. "fmt"
  16. "runtime"
  17. "github.com/golang/glog"
  18. )
  19. var (
  20. // ReallyCrash controls the behavior of HandleCrash and now defaults
  21. // true. It's still exposed so components can optionally set to false
  22. // to restore prior behavior.
  23. ReallyCrash = true
  24. )
  25. // PanicHandlers is a list of functions which will be invoked when a panic happens.
  26. var PanicHandlers = []func(interface{}){logPanic}
  27. // HandleCrash simply catches a crash and logs an error. Meant to be called via
  28. // defer. Additional context-specific handlers can be provided, and will be
  29. // called in case of panic. HandleCrash actually crashes, after calling the
  30. // handlers and logging the panic message.
  31. //
  32. // TODO: remove this function. We are switching to a world where it's safe for
  33. // apiserver to panic, since it will be restarted by kubelet. At the beginning
  34. // of the Kubernetes project, nothing was going to restart apiserver and so
  35. // catching panics was important. But it's actually much simpler for montoring
  36. // software if we just exit when an unexpected panic happens.
  37. func HandleCrash(additionalHandlers ...func(interface{})) {
  38. if r := recover(); r != nil {
  39. for _, fn := range PanicHandlers {
  40. fn(r)
  41. }
  42. for _, fn := range additionalHandlers {
  43. fn(r)
  44. }
  45. if ReallyCrash {
  46. // Actually proceed to panic.
  47. panic(r)
  48. }
  49. }
  50. }
  51. // logPanic logs the caller tree when a panic occurs.
  52. func logPanic(r interface{}) {
  53. callers := getCallers(r)
  54. glog.Errorf("Observed a panic: %#v (%v)\n%v", r, r, callers)
  55. }
  56. func getCallers(r interface{}) string {
  57. callers := ""
  58. for i := 0; true; i++ {
  59. _, file, line, ok := runtime.Caller(i)
  60. if !ok {
  61. break
  62. }
  63. callers = callers + fmt.Sprintf("%v:%v\n", file, line)
  64. }
  65. return callers
  66. }
  67. // ErrorHandlers is a list of functions which will be invoked when an unreturnable
  68. // error occurs.
  69. var ErrorHandlers = []func(error){logError}
  70. // HandlerError is a method to invoke when a non-user facing piece of code cannot
  71. // return an error and needs to indicate it has been ignored. Invoking this method
  72. // is preferable to logging the error - the default behavior is to log but the
  73. // errors may be sent to a remote server for analysis.
  74. func HandleError(err error) {
  75. // this is sometimes called with a nil error. We probably shouldn't fail and should do nothing instead
  76. if err == nil {
  77. return
  78. }
  79. for _, fn := range ErrorHandlers {
  80. fn(err)
  81. }
  82. }
  83. // logError prints an error with the call stack of the location it was reported
  84. func logError(err error) {
  85. glog.ErrorDepth(2, err)
  86. }
  87. // GetCaller returns the caller of the function that calls it.
  88. func GetCaller() string {
  89. var pc [1]uintptr
  90. runtime.Callers(3, pc[:])
  91. f := runtime.FuncForPC(pc[0])
  92. if f == nil {
  93. return fmt.Sprintf("Unable to find caller")
  94. }
  95. return f.Name()
  96. }
  97. // RecoverFromPanic replaces the specified error with an error containing the
  98. // original error, and the call tree when a panic occurs. This enables error
  99. // handlers to handle errors and panics the same way.
  100. func RecoverFromPanic(err *error) {
  101. if r := recover(); r != nil {
  102. callers := getCallers(r)
  103. *err = fmt.Errorf(
  104. "recovered from panic %q. (err=%v) Call stack:\n%v",
  105. r,
  106. *err,
  107. callers)
  108. }
  109. }