Skip to content

Commit 5619568

Browse files
committed
[FAB-6386] Update error handling documentation
This CR updates the error handling documentation to reflect the (relatively) newly vendored github.com/pkg/errors, its usage, and general guidelines for use within Fabric code. Change-Id: I8f727e2489a267611fa50238d9a2d848335beac0 Signed-off-by: Will Lahti <wtlahti@us.ibm.com>
1 parent 9227a52 commit 5619568

File tree

1 file changed

+63
-126
lines changed

1 file changed

+63
-126
lines changed

docs/source/error-handling.rst

Lines changed: 63 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3,148 +3,85 @@ Error handling
33

44
General Overview
55
----------------
6-
The Hyperledger Fabric error handling framework can be found in the source
7-
repository under **common/errors**. It defines a new type of error,
8-
CallStackError, to use in place of the standard error type provided by Go.
9-
10-
A CallStackError consists of the following:
11-
12-
- Component code - a name for the general area of the code that is generating
13-
the error. Component codes should consist of three uppercase letters. Numerics
14-
and special characters are not allowed. A set of component codes is defined
15-
in common/errors/codes.go
16-
- Reason code - a short code to help identify the reason the error occurred.
17-
Reason codes should consist of three numeric values. Letters and special
18-
characters are not allowed. A set of reason codes is defined in
19-
common/error/codes.go
20-
- Error code - the component code and reason code separated by a colon,
21-
e.g. MSP:404
22-
- Error message - the text that describes the error. This is the same as the
23-
input provided to ``fmt.Errorf()`` and ``Errors.New()``. If an error has been
24-
wrapped into the current error, its message will be appended.
25-
- Callstack - the callstack at the time the error is created. If an error has
26-
been wrapped into the current error, its error message and callstack will be
27-
appended to retain the context of the wrapped error.
28-
29-
The CallStackError interface exposes the following functions:
30-
31-
- Error() - returns the error message with callstack appended
32-
- Message() - returns the error message (without callstack appended)
33-
- GetComponentCode() - returns the 3-character component code
34-
- GetReasonCode() - returns the 3-digit reason code
35-
- GetErrorCode() - returns the error code, which is "component:reason"
36-
- GetStack() - returns just the callstack
37-
- WrapError(error) - wraps the provided error into the CallStackError
6+
Hyperledger Fabric code should use the vendored package
7+
**github.com/pkg/errors** in place of the standard error type provided by Go.
8+
This package allows easy generation and display of stack traces with error
9+
messages.
3810

3911
Usage Instructions
4012
------------------
4113

42-
The new error handling framework should be used in place of all calls to
43-
``fmt.Errorf()`` or ``Errors.new()``. Using this framework will provide error
44-
codes to check against as well as the option to generate a callstack that will be
45-
appended to the error message.
14+
**github.com/pkg/errors** should be used in place of all calls to
15+
``fmt.Errorf()`` or ``errors.New()``. Using this package will generate a
16+
call stack that will be appended to the error message.
4617

47-
Using the framework is simple and will only require an easy tweak to your code.
18+
Using this package is simple and will only require easy tweaks to your code.
4819

49-
First, you'll need to import **github.com/hyperledger/fabric/common/errors** into
50-
any file that uses this framework.
20+
First, you'll need to import **github.com/pkg/errors**.
5121

52-
Let's take the following as an example from core/chaincode/chaincode_support.go:
22+
Next, update all errors that are generated by your code to use one of the error
23+
creation functions (errors.New(), errors.Errorf(), errors.WithMessage(),
24+
errors.Wrap(), errors.Wrapf().
5325

54-
.. code:: go
55-
56-
err = fmt.Errorf("Error starting container: %s", err)
57-
58-
For this error, we will simply call the constructor for Error and pass a
59-
component code, reason code, followed by the error message. At the end, we
60-
then call the ``WrapError()`` function, passing along the error itself.
61-
62-
.. code:: go
63-
64-
fmt.Errorf("Error starting container: %s", err)
65-
66-
becomes
67-
68-
.. code:: go
69-
70-
errors.ErrorWithCallstack("CHA", "505", "Error starting container").WrapError(err)
71-
72-
You could also just leave the message as is without any problems:
73-
74-
.. code:: go
75-
76-
errors.ErrorWithCallstack("CHA", "505", "Error starting container: %s", err)
77-
78-
With this usage you will be able to format the error message from the previous
79-
error into the new error, but will lose the ability to print the callstack (if
80-
the wrapped error is a CallStackError).
81-
82-
A second example to highlight a scenario that involves formatting directives for
83-
parameters other than errors, while still wrapping an error, is as follows:
84-
85-
.. code:: go
86-
87-
fmt.Errorf("failed to get deployment payload %s - %s", canName, err)
88-
89-
becomes
90-
91-
.. code:: go
92-
93-
errors.ErrorWithCallstack("CHA", "506", "Failed to get deployment payload %s", canName).WrapError(err)
26+
.. note:: See https://godoc.org/github.com/pkg/errors for complete documentation
27+
of the available error creation function. Also, refer to the General guidelines
28+
section below for more specific guidelines for using the package for Fabric
29+
code.
9430

95-
Displaying error messages
96-
-------------------------
31+
Finally, change the formatting directive for any logger or fmt.Printf() calls
32+
from ``%s`` to ``%+v`` to print the call stack along with the error message.
9733

98-
Once the error has been created using the framework, displaying the error
99-
message is as simple as:
100-
101-
.. code:: go
102-
103-
logger.Errorf(err)
104-
105-
or
106-
107-
.. code:: go
108-
109-
fmt.Println(err)
110-
111-
or
34+
General guidelines for error handling in Hyperledger Fabric
35+
-----------------------------------------------------------
11236

113-
.. code:: go
37+
- If you are servicing a user request, you should log the error and return it.
38+
- If the error comes from an external source, such as a Go library or vendored
39+
package, wrap the error using errors.Wrap() to generate a call stack for the
40+
error.
41+
- If the error comes from another Fabric function, add further context, if
42+
desired, to the error message using errors.WithMessage() while leaving the
43+
call stack unaffected.
44+
- A panic should not be allowed to propagate to other packages.
11445

115-
fmt.Printf("%s\n", err)
46+
Example program
47+
---------------
11648

117-
An example from peer/common/common.go:
49+
The following example program provides a clear demonstration of using the
50+
package:
11851

11952
.. code:: go
12053
121-
errors.ErrorWithCallstack("PER", "404", "Error trying to connect to local peer").WrapError(err)
122-
123-
would display the error message:
124-
125-
.. code:: bash
126-
127-
PER:404 - Error trying to connect to local peer
128-
Caused by: grpc: timed out when dialing
129-
130-
.. note:: The callstacks have not been displayed for this example for the sake of
131-
brevity.
132-
133-
General guidelines for error handling in Hyperledger Fabric
134-
-----------------------------------------------------------
135-
136-
- If it is some sort of best effort thing you are doing, you should log the
137-
error and ignore it.
138-
- If you are servicing a user request, you should log the error and return it.
139-
- If the error comes from elsewhere, you have the choice to wrap the error
140-
or not. Typically, it's best to not wrap the error and simply return
141-
it as is. However, for certain cases where a utility function is called,
142-
wrapping the error with a new component and reason code can help an end user
143-
understand where the error is really occurring without inspecting the callstack.
144-
- A panic should be handled within the same layer by throwing an internal error
145-
code/start a recovery process and should not be allowed to propagate to other
146-
packages.
54+
package main
55+
56+
import (
57+
"fmt"
58+
59+
"github.com/pkg/errors"
60+
)
61+
62+
func wrapWithStack() error {
63+
err := createError()
64+
// do this when error comes from external source (go lib or vendor)
65+
return errors.Wrap(err, "wrapping an error with stack")
66+
}
67+
func wrapWithoutStack() error {
68+
err := createError()
69+
// do this when error comes from internal Fabric since it already has stack trace
70+
return errors.WithMessage(err, "wrapping an error without stack")
71+
}
72+
func createError() error {
73+
return errors.New("original error")
74+
}
75+
76+
func main() {
77+
err := createError()
78+
fmt.Printf("print error without stack: %s\n\n", err)
79+
fmt.Printf("print error with stack: %+v\n\n", err)
80+
err = wrapWithoutStack()
81+
fmt.Printf("%+v\n\n", err)
82+
err = wrapWithStack()
83+
fmt.Printf("%+v\n\n", err)
84+
}
14785
14886
.. Licensed under Creative Commons Attribution 4.0 International License
14987
https://creativecommons.org/licenses/by/4.0/
150-

0 commit comments

Comments
 (0)