docs/content/en/project/contributing/contributing-error.md
Meshery pervasively uses MeshKit as a golang and infrastructure management-specific library in all of its components. MeshKit helps populate error messages with a uniform and useful set of informative attributes.
To help with creating error codes, MeshKit contains a tool that analyzes, verifies and updates error codes in Meshery source code trees. It extracts error details into a file that can be used for publishing all error code references on the Meshery [error codes reference page]({{< ref "reference/references/error-codes.md" >}}). The objective to create this was to avoid centralized handling of error codes and automating everything
In order to create a Meshery error object, you will need to create a custom wrapper object for the native golang error. This can be done from the <a href="https://github.com/meshery/meshkit/tree/master/errors">MeshKit Error</a> package.
This tool will create a couple of files, one of them is designed to be used to generate the error reference on the Meshery Documentation website. The file errorutil_analyze_summary.json contains a summary of the analysis, notably lists of duplicates etc.
make error analyzes your code and returns any warnings to be aware of.Use the errors.New() function to create a new instance of the error object and pass situation-specific attributes as function arguments. These attributes are:
{{< code code=errors.New(ErrExampleCode, errors.Alert, []string{"<short-description>"}, []string{"<long-description>"}, []string{"<probable-cause>"}, []string{"<suggested remediation>"}) >}}
In this example we are creating an Error for being unable to marshal JSON
{{< code code=`var ( // Error code ErrMarshalCode= "replace_me"
//Static errors (for example)
ErrExample = errors.New(ErrExampleCode, errors.Alert, []string{"<short-description>"}, []string{"<long-description>"}, []string{"<probable-cause>"}, []string{"<suggested remediation>"})
)
// Dynamic errors //Error Name func ErrMarshal(err error, obj string) error { return errors.New(ErrMarshalCode, errors.Alert, []string{"Unable to marshal the : ", obj}, []string{err.Error()}, []string{}, []string{}) }` >}}
Old
{{< code code=bd, err := json.Marshal(providers) if err != nil { http.Error(w, "unable to marshal the providers", http.StatusInternalServerError) return } >}}
New
{{< code code=bd, err := json.Marshal(providers) if err != nil { obj := "provider" http.Error(w, ErrMarshal(err, obj).Error(), http.StatusInternalServerError) return } >}}
There already exists an interface for logger in MeshKit.
{{% alert color="warning" title="WARNING" %}} To enforce the use of meshkit errors, meshkit logger was designed such that it only works with meshkit errors. If a non-meshkit error is logged through the logger, it would panic and kill the process. See: meshkit#119 for more insight. {{% /alert %}}
{{< code code=type Logger struct { log logger.Handler } >}}
{{< code code=logrus.Debugf("meshLocationURL: %s", meshLocationURL) >}}
{{< code code=l.log.Debug("meshLocationURL: ", meshLocationURL) >}}
{{< code code=logrus.Errorf("error marshaling data: %v.", err) >}}
{{< code code=l.log.Error(ErrMarshal(err, obj)) >}}
{{< code code=`package main
import ( "fmt" "os"
meshkitErrors "github.com/meshery/meshkit/errors"
"github.com/meshery/meshkit/logger"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
var ( // CI will replace test_code with new error code ErrOpeningFileCode = "test_code" )
func main() { logLevel := viper.GetInt("LOG_LEVEL") if viper.GetBool("DEBUG") { logLevel = int(logrus.DebugLevel) } log, err := logger.New("test", logger.Options{ Format: logger.SyslogLogFormat, LogLevel: logLevel, }) if err != nil { fmt.Println(err) os.Exit(1) }
// logging meshkit error
err = openFileWithMeshkitError("some.txt")
if err != nil {
log.Error(err)
}
// OUTPUT
// ERRO[2021-11-10T17:31:28+05:30] open some.txt: no such file or directory
// app=test code=1001 probable-cause="empty string passed as argument .file with this name doesn't exist"
// severity=2 short-description="unable to open file" suggested-remediation="pass a non-empty string as
// filename .create file before opening it"
// logging non meshkit error
err = openFile("some.txt")
if err != nil {
log.Error(err)
}
// OUTPUT
// ERRO[2024-07-01T19:09:09+05:30] open some.txt: no such file or directory
// app=test code= probable-cause= severity=0 short-description= suggested-remediation=
}
// this returns a non meshkit error func openFile(name string) error { _, err := os.Open(name) return err }
// this returns a meshkit error func openFileWithMeshkitError(name string) error { _, err := os.Open(name) return ErrOpeningFile(err) }
func ErrOpeningFile(err error) error { return meshkitErrors.New(ErrOpeningFileCode, meshkitErrors.Alert, []string{"unable to open file"}, []string{err.Error()}, []string{"empty string passed as argument ", "file with this name doesn't exist"}, []string{"pass a non-empty string as filename ", "create file before opening it"}) }` >}}