@@ -3,148 +3,85 @@ Error handling
3
3
4
4
General Overview
5
5
----------------
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.
38
10
39
11
Usage Instructions
40
12
------------------
41
13
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.
46
17
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.
48
19
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 **.
51
21
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().
53
25
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.
94
30
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.
97
33
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
+ -----------------------------------------------------------
112
36
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.
114
45
115
- fmt.Printf("%s\n", err)
46
+ Example program
47
+ ---------------
116
48
117
- An example from peer/common/common.go:
49
+ The following example program provides a clear demonstration of using the
50
+ package:
118
51
119
52
.. code :: go
120
53
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
+ }
147
85
148
86
.. Licensed under Creative Commons Attribution 4.0 International License
149
87
https://creativecommons.org/licenses/by/4.0/
150
-
0 commit comments