Skip to content

Instantly share code, notes, and snippets.

@cirocosta
Created November 6, 2018 02:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cirocosta/d0b9cde1c79cc12a943a562a98ffd962 to your computer and use it in GitHub Desktop.
Save cirocosta/d0b9cde1c79cc12a943a562a98ffd962 to your computer and use it in GitHub Desktop.
Capturing errors on a deferred statement
package main
import (
"fmt"
"os"
"code.cloudfoundry.org/lager"
)
// methodThatFails simply always fails, returning an
// error every time (after logging its execution).
func methodThatFails(logger lager.Logger) (err error) {
logger.Debug("method-that-fails")
err = fmt.Errorf("method-that-fails")
return
}
// method2 implements does the same as `method1`, except
// for the fact that it captures the error before returning.
//
// Once executed, although `methodThatFails` always fails, we
// see the following logs:
//
// DEBUG: start
// ERROR: fail: err=method-that-fails
//
func method2(logger lager.Logger) (err error) {
sess := logger.Session("method2")
sess.Debug("start")
defer func() {
if err != nil {
// By always assigning to `err` before
// returning, we make sure that the variable
// `err` gets properly set.
//
// Given that this `defer` gets called before
// we end the execution of this method, we have
// the behavior we expect.
sess.Error("fail", err)
return
}
sess.Debug("finished")
}()
err = methodThatFails(sess)
return
}
// method1 implements a defer statement that "feels like"
// it does the right thing (capturing the error before exiting),
// except that it doesn't.
//
// Once executed, although `methodThatFails` always fails, we
// see the following logs:
//
// DEBUG: start
// DEBUG: finished
//
func method1(logger lager.Logger) error {
var (
err error
sess = logger.Session("session")
)
sess.Debug("start")
defer func() {
if err != nil {
// Won't *EVER* reach this branch given that
// we're never setting `err` to the value of
// the error before returning.
sess.Error("fail", err)
return
}
sess.Debug("finished")
}()
return methodThatFails(sess)
}
func main() {
logger := lager.NewLogger("main")
logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.DEBUG))
method1(logger)
method2(logger)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment