func unsafeLogWith(err error, logger log.Logger) error { // Handle errors implementing Err interface. if ex, ok := err.(Err); ok { logger.UnsafeFail(ex.Task()) hint := ex.Hint() if next, ok := ex.Err().(Err); ok { // The next error is also Err, call recursively // after printing the hint when that is set. logger.UnsafeStderr(hint) return unsafeLogWith(next, logger) } else { // The next error is the root cause error. // It is not implementing Err, so we can print // the root cause error and stop the recursion. last := ex.Err() logger.UnsafeNewLine(fmt.Sprintf("(error = %v)", last)) logger.UnsafeStderr(hint) return last } } // Handle regular errors. // // This block is only executed when this function is called // for the first time with an error not implementing Err. logger.UnsafeFail("Unknown task") logger.UnsafeNewLine(fmt.Sprintf("(error = %v)", err)) return err }
// LogWith logs the given error using the given logger. func LogWith(err error, logger log.Logger) error { logger.Lock() defer logger.Unlock() return unsafeLogWith(err, logger) }