Skip to content

Commit 555686d

Browse files
committed
[FAB-2985] Add documentation for error handling
This change adds documentation for the error handling framework, which will soon be utilized throughout the Fabric codebase. Added formatting for codeblocks, notes, code syntax, etc... Condense Title to Error handling [ci-skip] Change-Id: Ia6dc94080314d43cf1bdb4c685bcc87856817f64 Signed-off-by: Will Lahti <[email protected]> Signed-off-by: Nick Gaski <[email protected]>
1 parent 852997a commit 555686d

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

docs/source/error-handling.rst

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
Error handling
2+
==============
3+
4+
General Overview
5+
----------------
6+
The Fabric error handling framework can be found in the Fabric repository under
7+
common/errors. It defines a new type of error, CallStackError, to use in place of
8+
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.
15+
16+
.. note:: Make sure to use a consistent component name across code in related
17+
files/packages.
18+
Examples of component codes (with their full component name in parentheses)
19+
are: CSP (bccsp), CMN (common), COR (core), CCS (core/chaincode), CDS
20+
(core/deliverservice), SCC (core/scc), EVT (events), GSP (gossip), LGR
21+
(ledger), PER (peer), ORD (orderer)
22+
23+
We may, in the future, add constants to allow searching for currently defined
24+
components for those using an editor with code completion capabilities.
25+
26+
- Reason code - a short code to help identify the reason the error occurred.
27+
Reason codes should consist of three numeric values. Letters and special
28+
characters are not allowed.
29+
30+
- Error code - the component code and reason code separated by a colon,
31+
e.g. PER:404
32+
33+
- Error message - the text that describes the error. This is the same as the
34+
input provided to ``fmt.Errorf()`` and ``Errors.New()``. If an error has been
35+
wrapped into the current error, its message will be appended.
36+
37+
- Callstack - the callstack at the time the error is created. If an error has
38+
been wrapped into the current error, its error message and callstack will be
39+
appended to retain the context of the wrapped error.
40+
41+
The CallStackError interface exposes the following functions:
42+
- Error() - returns the error message with callstack appended
43+
- Message() - returns the error message (without callstack appended)
44+
- GetComponentCode()
45+
- GetReasonCode()
46+
- GetErrorCode()
47+
- GetStack() - returns just the callstack
48+
- WrapError(error) - wraps the provided error into the CallStackError
49+
50+
Usage Instructions
51+
------------------
52+
53+
The new error handling framework should be used in place of all calls to
54+
``fmt.Errorf()`` or ``Errors.new()``. Using this framework will provide error
55+
codes to check against as well as the option to generate a callstack that will be
56+
appended to the error message.
57+
58+
Using the framework is simple and will only require an easy tweak to your code.
59+
60+
First, you'll need to import **github.com/hyperledger/fabric/common/errors** into
61+
any file that uses this framework.
62+
63+
Let's take the following as an example from core/chaincode/chaincode_support.go:
64+
65+
.. code:: go
66+
67+
err = fmt.Errorf("Error starting container: %s", err)
68+
69+
For this error, we will simply call the constructor for Error and pass a
70+
component code, reason code, followed by the error message. At the end, we
71+
then call the ``WrapError()`` function, passing along the error itself.
72+
73+
.. code:: go
74+
75+
fmt.Errorf("Error starting container: %s", err)
76+
77+
becomes
78+
79+
.. code:: go
80+
81+
errors.ErrorWithCallstack("CHA", "505", "Error starting container").WrapError(err)
82+
83+
You could also just leave the message as is without any problems:
84+
85+
.. code:: go
86+
87+
errors.ErrorWithCallstack("CHA", "505", "Error starting container: %s", err)
88+
89+
With this usage you will be able to format the error message from the previous
90+
error into the new error, but will lose the ability to print the callstack (if
91+
the wrapped error is a CallStackError).
92+
93+
A second example to highlight a scenario that involves formatting directives for
94+
parameters other than errors, while still wrapping an error, is as follows:
95+
96+
.. code:: go
97+
98+
fmt.Errorf("failed to get deployment payload %s - %s", canName, err)
99+
100+
becomes
101+
102+
.. code:: go
103+
104+
errors.ErrorWithCallstack("CHA", "506", "Failed to get deployment payload %s", canName).WrapError(err)
105+
106+
Displaying error messages
107+
-------------------------
108+
109+
Once the error has been created using the framework, displaying the error
110+
message is as simple as:
111+
112+
.. code:: go
113+
114+
logger.Errorf(err)
115+
116+
or
117+
118+
.. code:: go
119+
120+
fmt.Println(err)
121+
122+
or
123+
124+
.. code:: go
125+
126+
fmt.Printf("%s\n", err)
127+
128+
An example from peer/common/common.go:
129+
130+
.. code:: go
131+
132+
errors.ErrorWithCallstack("PER", "404", "Error trying to connect to local peer").WrapError(err)
133+
134+
would display the error message:
135+
136+
.. code:: bash
137+
138+
PER:404 - Error trying to connect to local peer
139+
Caused by: grpc: timed out when dialing
140+
141+
.. note:: The callstacks have not been displayed for this example for the sake of
142+
brevity.
143+
144+
General guidelines for error handling in Fabric
145+
-----------------------------------------------
146+
147+
- If it is some sort of best effort thing you are doing, you should log the
148+
error and ignore it.
149+
- If you are servicing a user request, you should log the error and return it.
150+
- If the error comes from elsewhere in the Fabric, you have the choice to wrap
151+
the error or not. Typically, it's best to not wrap the error and simply return
152+
it as is. However, for certain cases where a utility function is called,
153+
wrapping the error with a new component and reason code can help an end user
154+
understand where the error is really occurring without inspecting the callstack.
155+
- A panic should be handled within the same layer by throwing an internal error
156+
code/start a recovery process and should not be allowed to propagate to other
157+
packages.

0 commit comments

Comments
 (0)