mirror of
https://github.com/golang/go
synced 2024-11-24 19:40:09 -07:00
a40065ac68
doc: convert to use godoc built-in templates tmpltohtml is gone, to avoid having a second copy of the code. Instead, godoc -url /doc/go1.html will print the actual HTML served for that URL. "make" will generate files named go1.rawhtml etc, which can be fed through tidy. It can be hard to tell from the codereview diffs, but all the tmpl files have been renamed to be html files and then have "Template": true added. R=golang-dev, adg, r, gri CC=golang-dev https://golang.org/cl/5782046
316 lines
10 KiB
HTML
316 lines
10 KiB
HTML
<!--{
|
|
"Title": "Error Handling and Go",
|
|
"Template": true
|
|
}-->
|
|
|
|
<p>
|
|
If you have written any Go code you have probably encountered the built-in
|
|
<code>error</code> type. Go code uses <code>error</code> values to
|
|
indicate an abnormal state. For example, the <code>os.Open</code> function
|
|
returns a non-nil <code>error</code> value when it fails to open a file.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func Open/`}}
|
|
|
|
<p>
|
|
The following code uses <code>os.Open</code> to open a file. If an error
|
|
occurs it calls <code>log.Fatal</code> to print the error message and stop.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func openFile/` `/STOP/`}}
|
|
|
|
<p>
|
|
You can get a lot done in Go knowing just this about the <code>error</code>
|
|
type, but in this article we'll take a closer look at <code>error</code> and
|
|
discuss some good practices for error handling in Go.
|
|
</p>
|
|
|
|
<p>
|
|
<b>The error type</b>
|
|
</p>
|
|
|
|
<p>
|
|
The <code>error</code> type is an interface type. An <code>error</code>
|
|
variable represents any value that can describe itself as a string. Here is the
|
|
interface's declaration:
|
|
</p>
|
|
|
|
<pre>type error interface {
|
|
Error() string
|
|
}</pre>
|
|
|
|
<p>
|
|
The <code>error</code> type, as with all built in types, is
|
|
<a href="/doc/go_spec.html#Predeclared_identifiers">predeclared</a> in the
|
|
<a href="/doc/go_spec.html#Blocks">universe block</a>.
|
|
</p>
|
|
|
|
<p>
|
|
The most commonly-used <code>error</code> implementation is the
|
|
<a href="/pkg/errors/">errors</a> package's unexported <code>errorString</code> type.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/errorString/` `/STOP/`}}
|
|
|
|
<p>
|
|
You can construct one of these values with the <code>errors.New</code>
|
|
function. It takes a string that it converts to an <code>errors.errorString</code>
|
|
and returns as an <code>error</code> value.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/New/` `/STOP/`}}
|
|
|
|
<p>
|
|
Here's how you might use <code>errors.New</code>:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func Sqrt/` `/STOP/`}}
|
|
|
|
<p>
|
|
A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
|
<code>error</code> value (whose concrete representation is an
|
|
<code>errors.errorString</code> value). The caller can access the error string
|
|
("math: square root of...") by calling the <code>error</code>'s
|
|
<code>Error</code> method, or by just printing it:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func printErr/` `/STOP/`}}
|
|
|
|
<p>
|
|
The <a href="/pkg/fmt/">fmt</a> package formats an <code>error</code> value
|
|
by calling its <code>Error() string</code> method.
|
|
</p>
|
|
|
|
<p>
|
|
It is the error implementation's responsibility to summarize the context.
|
|
The error returned by <code>os.Open</code> formats as "open /etc/passwd:
|
|
permission denied," not just "permission denied." The error returned by our
|
|
<code>Sqrt</code> is missing information about the invalid argument.
|
|
</p>
|
|
|
|
<p>
|
|
To add that information, a useful function is the <code>fmt</code> package's
|
|
<code>Errorf</code>. It formats a string according to <code>Printf</code>'s
|
|
rules and returns it as an <code>error</code> created by
|
|
<code>errors.New</code>.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/fmtError/` `/STOP/`}}
|
|
|
|
<p>
|
|
In many cases <code>fmt.Errorf</code> is good enough, but since
|
|
<code>error</code> is an interface, you can use arbitrary data structures as
|
|
error values, to allow callers to inspect the details of the error.
|
|
</p>
|
|
|
|
<p>
|
|
For instance, our hypothetical callers might want to recover the invalid
|
|
argument passed to <code>Sqrt</code>. We can enable that by defining a new
|
|
error implementation instead of using <code>errors.errorString</code>:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/type NegativeSqrtError/` `/STOP/`}}
|
|
|
|
<p>
|
|
A sophisticated caller can then use a
|
|
<a href="/doc/go_spec.html#Type_assertions">type assertion</a> to check for a
|
|
<code>NegativeSqrtError</code> and handle it specially, while callers that just
|
|
pass the error to <code>fmt.Println</code> or <code>log.Fatal</code> will see
|
|
no change in behavior.
|
|
</p>
|
|
|
|
<p>
|
|
As another example, the <a href="/pkg/encoding/json/">json</a> package specifies a
|
|
<code>SyntaxError</code> type that the <code>json.Decode</code> function
|
|
returns when it encounters a syntax error parsing a JSON blob.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/type SyntaxError/` `/STOP/`}}
|
|
|
|
<p>
|
|
The <code>Offset</code> field isn't even shown in the default formatting of the
|
|
error, but callers can use it to add file and line information to their error
|
|
messages:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func decodeError/` `/STOP/`}}
|
|
|
|
<p>
|
|
(This is a slightly simplified version of some
|
|
<a href="http://camlistore.org/code/?p=camlistore.git;a=blob;f=lib/go/camli/jsonconfig/eval.go#l68">actual code</a>
|
|
from the <a href="http://camlistore.org">Camlistore</a> project.)
|
|
</p>
|
|
|
|
<p>
|
|
The <code>error</code> interface requires only a <code>Error</code> method;
|
|
specific error implementations might have additional methods. For instance, the
|
|
<a href="/pkg/net/">net</a> package returns errors of type
|
|
<code>error</code>, following the usual convention, but some of the error
|
|
implementations have additional methods defined by the <code>net.Error</code>
|
|
interface:
|
|
</p>
|
|
|
|
<pre>package net
|
|
|
|
type Error interface {
|
|
error
|
|
Timeout() bool // Is the error a timeout?
|
|
Temporary() bool // Is the error temporary?
|
|
}</pre>
|
|
|
|
<p>
|
|
Client code can test for a <code>net.Error</code> with a type assertion and
|
|
then distinguish transient network errors from permanent ones. For instance, a
|
|
web crawler might sleep and retry when it encounters a temporary error and give
|
|
up otherwise.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error.go" `/func netError/` `/STOP/`}}
|
|
|
|
<p>
|
|
<b>Simplifying repetitive error handling</b>
|
|
</p>
|
|
|
|
<p>
|
|
In Go, error handling is important. The language's design and conventions
|
|
encourage you to explicitly check for errors where they occur (as distinct from
|
|
the convention in other languages of throwing exceptions and sometimes catching
|
|
them). In some cases this makes Go code verbose, but fortunately there are some
|
|
techniques you can use to minimize repetitive error handling.
|
|
</p>
|
|
|
|
<p>
|
|
Consider an <a href="http://code.google.com/appengine/docs/go/">App Engine</a>
|
|
application with an HTTP handler that retrieves a record from the datastore and
|
|
formats it with a template.
|
|
</p>
|
|
|
|
{{code "/doc/progs/error2.go" `/func init/` `/STOP/`}}
|
|
|
|
<p>
|
|
This function handles errors returned by the <code>datastore.Get</code>
|
|
function and <code>viewTemplate</code>'s <code>Execute</code> method. In both
|
|
cases, it presents a simple error message to the user with the HTTP status code
|
|
500 ("Internal Server Error"). This looks like a manageable amount of code, but
|
|
add some more HTTP handlers and you quickly end up with many copies of
|
|
identical error handling code.
|
|
</p>
|
|
|
|
<p>
|
|
To reduce the repetition we can define our own HTTP <code>appHandler</code>
|
|
type that includes an <code>error</code> return value:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error3.go" `/type appHandler/`}}
|
|
|
|
<p>
|
|
Then we can change our <code>viewRecord</code> function to return errors:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error3.go" `/func viewRecord/` `/STOP/`}}
|
|
|
|
<p>
|
|
This is simpler than the original version, but the <a
|
|
href="/pkg/net/http/">http</a> package doesn't understand functions that return
|
|
<code>error</code>.
|
|
To fix this we can implement the <code>http.Handler</code> interface's
|
|
<code>ServeHTTP</code> method on <code>appHandler</code>:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error3.go" `/ServeHTTP/` `/STOP/`}}
|
|
|
|
<p>
|
|
The <code>ServeHTTP</code> method calls the <code>appHandler</code> function
|
|
and displays the returned error (if any) to the user. Notice that the method's
|
|
receiver, <code>fn</code>, is a function. (Go can do that!) The method invokes
|
|
the function by calling the receiver in the expression <code>fn(w, r)</code>.
|
|
</p>
|
|
|
|
<p>
|
|
Now when registering <code>viewRecord</code> with the http package we use the
|
|
<code>Handle</code> function (instead of <code>HandleFunc</code>) as
|
|
<code>appHandler</code> is an <code>http.Handler</code> (not an
|
|
<code>http.HandlerFunc</code>).
|
|
</p>
|
|
|
|
{{code "/doc/progs/error3.go" `/func init/` `/STOP/`}}
|
|
|
|
<p>
|
|
With this basic error handling infrastructure in place, we can make it more
|
|
user friendly. Rather than just displaying the error string, it would be better
|
|
to give the user a simple error message with an appropriate HTTP status code,
|
|
while logging the full error to the App Engine developer console for debugging
|
|
purposes.
|
|
</p>
|
|
|
|
<p>
|
|
To do this we create an <code>appError</code> struct containing an
|
|
<code>error</code> and some other fields:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error4.go" `/type appError/` `/STOP/`}}
|
|
|
|
<p>
|
|
Next we modify the appHandler type to return <code>*appError</code> values:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error4.go" `/type appHandler/`}}
|
|
|
|
<p>
|
|
(It's usually a mistake to pass back the concrete type of an error rather than
|
|
<code>error</code>, for reasons to be discussed in another article, but
|
|
it's the right thing to do here because <code>ServeHTTP</code> is the only
|
|
place that sees the value and uses its contents.)
|
|
</p>
|
|
|
|
<p>
|
|
And make <code>appHandler</code>'s <code>ServeHTTP</code> method display the
|
|
<code>appError</code>'s <code>Message</code> to the user with the correct HTTP
|
|
status <code>Code</code> and log the full <code>Error</code> to the developer
|
|
console:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error4.go" `/ServeHTTP/` `/STOP/`}}
|
|
|
|
<p>
|
|
Finally, we update <code>viewRecord</code> to the new function signature and
|
|
have it return more context when it encounters an error:
|
|
</p>
|
|
|
|
{{code "/doc/progs/error4.go" `/func viewRecord/` `/STOP/`}}
|
|
|
|
<p>
|
|
This version of <code>viewRecord</code> is the same length as the original, but
|
|
now each of those lines has specific meaning and we are providing a friendlier
|
|
user experience.
|
|
</p>
|
|
|
|
<p>
|
|
It doesn't end there; we can further improve the error handling in our
|
|
application. Some ideas:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>give the error handler a pretty HTML template,
|
|
<li>make debugging easier by writing the stack trace to the HTTP response when
|
|
the user is an administrator,
|
|
<li>write a constructor function for <code>appError</code> that stores the
|
|
stack trace for easier debugging,
|
|
<li>recover from panics inside the <code>appHandler</code>, logging the error
|
|
to the console as "Critical," while telling the user "a serious error
|
|
has occurred." This is a nice touch to avoid exposing the user to inscrutable
|
|
error messages caused by programming errors.
|
|
See the <a href="defer_panic_recover.html">Defer, Panic, and Recover</a>
|
|
article for more details.
|
|
</ul>
|
|
|
|
<p>
|
|
<b>Conclusion</b>
|
|
</p>
|
|
|
|
<p>
|
|
Proper error handling is an essential requirement of good software. By
|
|
employing the techniques described in this post you should be able to write
|
|
more reliable and succinct Go code.
|
|
</p>
|