This is a creation in Article, where the information may have evolved or changed. [Upspin] The (https://upspin.io/) project uses a custom package--[upspin.io/errors] (https://godoc.org/upspin.io/errors)--to represent error conditions that occur inside the system. These errors meet the standard Go [ERROR] (https://golang.org/pkg/builtin/#error) interface, but use a custom type [upspin.io/errors. Error] (Https://godoc.org/upspin.io/errors#Error), which has some properties that have proved useful to the project. Here, we will show how this package works and how to use this package. This story provides lessons for a broader discussion of error handling in Go. Motivation after a few months in the project, we are well aware that we need a consistent way to handle the construction, description, and handling of errors throughout the code. We decided to implement a custom errors package and launch it one afternoon. The details have changed compared to the initial implementation, but the basic idea behind the package is enduring. They are: * To facilitate the construction of useful error messages. * In order to make the user easy to understand the error. * In order to let the error help the programmer to diagnose the problem. As our experience in developing this package grows, there are some other requirements. Here's what we'll talk about. # # Errors Package tour [upspin.io/errors] (https://godoc.org/upspin.io/errors) package is imported with the package name "errors", so in Upspin, it replaces the Go standard "errors Package We notice that the elements of the error message in Upspin are of different types: User name, pathname, type of error (I/O, Permission, and so on), and so forth. This provides a starting point for the errors package, which will be built on top of these different types to build, represent, and report on errors that occur. The center of the package is the [ERROR] (HTTPS://GODOC.ORG/UPSPIN.IO/ERRORS#ERROR) type, which is a specific representation of a upspin error. It has multiple fields, and any field can be set without setting: "Go type Error struct {Path upspin. PathName User Upspin. UserName op op Kind Kind Err erROR} ' path and user fields represent the paths and users affected by the operation. Note that these are strings, but they are unique types in Upspin to indicate their purpose and allow the type system to catch certain types of programming errors. The Op field represents the action performed. It is another type of string that typically holds the method name or the name of the server function that reported the error: "Client." Lookup "," Dir/server. Glob "and so on. The Kind field classifies the error as a member of a set of standard conditions (Permission, IO, notexist,[, and so on] (Https://godoc.org/upspin.io/errors#Kind). This makes it easy to see a concise description of the type of error that appears, and also provides hooks for connecting to other systems. For example, [Upspinfs] (HTTPS://GODOC.ORG/UPSPIN.IO/CMD/UPSPINFS) uses the Kind field as a key to convert Upspin errors to Unix Error constants (for example, Eperm and EIO). The last field, ERR, saves another error value. This is usually an error from another system, such as a file system error for the [OS] (https://golang.org/pkg/os/) package, or a network error for the [NET] (https://golang.org/pkg/net/) package. It could also be another upspin.io/errors. error value to create a bug trace (we'll discuss later). # # Build Error in order to help build the error, this package provides a function called [E] (Https://godoc.org/upspin.io/errors#E), which is short and easy to enter. "' Gofunc e (args ... interface{}) error '" as described in [document comments] (Https://godoc.org/upspin.io/errors#E) of the function, E constructs an error value based on its input parameters. The type of each parameter determines its own meaning. The idea is to examine the type of each parameter, and then assign the value of the parameter to a field of the corresponding type in the constructed Error structure. Here is an obvious correspondence point: PathName corresponds to error.path,username corresponding to Error.user, and so on. Let's look at an example. Typically, multiple pairs of errors are present in a method. E is called, so we define a constant, which is known by Convention as OP, which is passed as a parameter to the methodAll E calls in: ' Gofunc (S *server) Delete (ref upspin. Reference) Error {const OP errors. Op = "server. Delete "..." then, throughout the method, we will use this constant as the first parameter of each E-call (although the actual order of the arguments is irrelevant, but as usual, OP is placed first): "' goif err: = Authorize (user); Err! = Nil {return errors. E (OP, User, errors. Permission, Err)} ' E ' is neatly formatted with the String method: ' ' Server. Delete:user ann@example.com:permission Denied:user Not authorized "If the error is nested in multiple levels, the redundant field is suppressed, and the nested is formatted with indentation: ' Client. Lookup:ann@example.com/file:item does not exist:dir/remote ("upspin.example.net:443"). Lookup:dir/server. The Lookup "Note that this error message mentions a variety of actions (client. Lookup,dir/remote,dir/server). In the following sections, we will discuss this multiplicity. Again, sometimes, the error is special and is clearly described at the point of invocation through a normal string. To make it work in an obvious way, the constructor passes a standard-like Go function [errors. New] (https://golang.org/pkg/errors/#New) to convert the literal type string argument to the Go error type. Therefore, it can be written like this: "' goerrors. E (OP, "unexpected Failure") "or" goerrors. E (OP, Fmt. SPRINTF ("Could not succeed after%d tries", Ntries) "will then give the string to the Err field of the result err type. This is a natural and simple way to build a special error. # # cross-network error Upspin is a distributed system, so it is critical that communication between Upspin servers retain the wrong structure. To doThis, we use the errors package of [Marshalerror] (Https://godoc.org/upspin.io/errors#MarshalError) and [Unmarshalerror] (https:// Godoc.org/upspin.io/errors#unmarshalerror) function to transfer code errors in the network connection, so that Upspin RPC knows these types of errors. These functions ensure that the client will see all the details provided by the server in the case of a construction error. Consider the following error report: "Client." Lookup:ann@example.com/test/file:item does not exist:dir/remote ("dir.example.com:443"). Lookup:dir/server. Lookup:store/remote ("store.example.com:443"). Get:fetching Https://storage.googleapis.com/bucket/C1AF ...: 404 Not Found "" It consists of four nested errors. E-Value composition. From the bottom up, the innermost part comes from the package [Upspin.io/store/remote] (http://upspin.io/store/remotehttps://godoc.org/upspin.io/store/remote ) (responsible for interacting with Remote Storage servers). This error indicates that there was a problem getting the object from the store. This error is probably built in such a way that it encapsulates a bottom-level error from the cloud storage provider: "' Goconst op errors. Op = ' Store/remote ("store.example.com:443"). Get ' var resp *http. Response...return errors. E (OP, errors. SPRINTF ("Fetching%s:%s", URL, resp. Status) "The next error comes from the directory server (package [Upspin.io/dir/server] (https://godoc.org/upspin.io/dir/server), our directory server reference implementation), This indicates that the directory server is attempting a lookup operation when an error occurs. This error is built like this: "' Goconst op errors. Op ="Dir/server. Lookup "... return errors. E (OP, PathName, errors. Notexist, err) ' This is the first layer, which adds a Kind (errors.notexist). Lookup error values are passed through the network (packaged and unpacked along the same journey), followed by [Upspin.io/dir/remote] (Https://godoc.org/upspin.io/dir/remote) The package (responsible for interacting with the remote directory server) passes through it itself to the errors. E's call to encapsulate this error: ' Go const OP errors. Op = "Dir/remote." Lookup "... return errors. E (OP, PathName, Err) "In this call, no Kind is set, so when building this Error structure, use the internal Kind (errors.notexist). Finally, the [upspin.io/client] (https://godoc.org/upspin.io/client) package once again encapsulates this error: "' Goconst op errors. Op = "client." Lookup "... return errors. E (OP, PathName, err) ' Reserved server error structure allows the client to programmatically know that this is a "not exist" error, and that the related item of the problem is "Ann@example.com/file". The error [ERROR] (Https://godoc.org/upspin.io/errors#Error.Error) method can take advantage of this structure to suppress redundant fields. If the server error is just a vague string, we'll see the path name more than once in the output. The key details (PathName and Kind) are pulled to the top of the error, so that they are more prominent in the presentation. The expectation is that when the user sees these errors, the first line of the error is usually sufficient, and the following details are more useful when further diagnosis is required. We turn our back on the false display as a whole, we can trace the error from generation to client through various network connection components. A complete error chain may help the user, but it will certainly help the system's implementation, which will help them determine whether the problem is unexpected or unusual. # # Users and implementations make errors useful to end users and remain concise, with the information rich and available for analysis for the error to the implementation, bothConflict between the two. Often the implementation wins, and the error becomes overly redundant, reaching the level of the stack trace or other submerged detail. Upspin's error attempts to satisfy both the user and the implementation. The reported errors are moderately concise and focus on the information that the user should find useful. But they also contain internal details, such as method implementations that can obtain diagnostic information without flooding the user. In practice, we find that this tradeoff works well. Conversely, errors similar to stack traces are worse in both respects. The user has no context to understand the stack trace, and if the server error is passed to the client, then it is difficult to see the information that should appear on the stack trace's implementation. This is why the Upspin error nesting is equivalent to the operation _ tracing (displaying the system element path), rather than _ executing the _ Trace (showing the Code execution path). This distinction is crucial. For scenarios where stack traces might be useful, we allow the "debug" tag to be used to build the errors package, which will allow the print stack trace. This works well, but it's worth noting that we almost never use this feature. Instead, the default behavior of the errors package is good enough to avoid the overhead and unsightly stack traces. # # Match Error Upspin one of the unintended benefits of custom error handling is the ease of writing error-dependent tests and writing error-sensitive code outside of tests. These usages are made possible by the two functions in the errors package. The first is a function called [errors. IS] (https://godoc.org/upspin.io/errors#Is), which returns a Boolean value that indicates whether the parameter err is *errors. The Error type, if it is, then its Kind field has a specific value. The "Gofunc is (kind kind, err error) bool" is a function that allows the code to directly alter behavior based on error conditions, for example, in the face of a permission error, unlike a network error: ' GOif errors. Is (errors. Permission, err) {...} Another function, [Match] (Https://godoc.org/upspin.io/errors#Match), is useful for testing. We created it when we had already used the errors package for some time and then found that too many of our tests were sensitive to error details. For example, a test might only need to check for permission errors that open a specific file, but is sensitive to the exact format of the error message. After fixing a lot of vulnerable tests like this, we wrote a function to report the error that was received err whether it matches an error template: "' GofunC Match (template, err error) bool "This function checks whether the error is *errors. Error type, and if so, whether the fields in the errors are equal to those fields in the template. The key is that it checks only those non-0 fields in the template, ignoring the other fields. For the above example, we can write: "' goif errors. Match (Errors. E (Errors. Permission, PathName), err) {...} "And is not affected by other properties of the error. In our tests, we used Match for countless times; it was a big surprise. # # Lessons in the Go community, there is a lot of discussion about how to deal with errors, and it is important to realize that there is no single answer to this question. There is no package or a way to meet the needs of all programs. As [here] (https://blog.golang.org/errors-are-values) points out, errors are just values and can be programmed in different ways to meet different scenarios. Upspin's errors bag is good for us. We are not arguing that for another system, it is the right answer, or even that this method is suitable for someone else. But this package is well-used in Upspin and teaches us some lessons worth documenting. Upspin the size of the errors pack and covers the range moderately. Its initial implementation was completed within a few hours, while the basic design was preserved and, since completion, experienced some improvements. It should also be easy to customize a bug package for another project. It should be easy to apply to the specific needs of any particular environment. Don't be afraid to try, just think first and be willing to try. When considering the details of your own project, think about what can be improved here. We make sure that the wrong constructor is easy to use and easy to read. If this is not the case, then the programmer can refuse to use it. The behavior of the errors package is based on the type of the underlying system in some degree. This is a small but important point: No general error package can do what we do. It is really a custom package. In addition, the use of different types of parameters makes the construction of errors fluent. This can be achieved by combining the existing types in the system (PathName, UserName) and the new types created for that purpose (OP, Kind). The Help type makes the error build clean, secure, and easy. It takes a bit of extra work (we have to create these types and then use them everywhere, for example through "const OP"), but the results are worthwhile. Finally, we want to emphasize that the lack of stack traces is part of the error model in Upspin. Conversely, erThe Rors packet reports the sequence of events (usually across the network), which produces errors that are passed to the client. Careful construction of errors through operations in the system can be simpler, more descriptive, and more useful than simple stack traces. The error is given to the user, not just to the programmer. (Errors is for users, not just for programmers.) _ from Rob Pike and Andrew Gerrand_
Via:https://commandcenter.blogspot.co.uk/2017/12/error-handling-in-upspin.html
Author: Rob Pike Translator: Ictar proofreading: Rxcai polaris1119
This article by GCTT original compilation, go language Chinese network honor launches
This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove
660 reads ∙1 likes