Documentation ¶
Overview ¶
This example demonstrates how to use the errors generated by ohnogen tool when generated with the -ohno flag. When you generate errors with the -ohno flag you will be able to use the enums as errors along with the ability to add additional context like a message, extra data, timestamp, source location etc by using the OhNo(...) method. Lets begin by defining a custom type MyFabulousOhNoError
Index ¶
- type MyFabulousOhNoError
- func (i MyFabulousOhNoError) Code() string
- func (i MyFabulousOhNoError) Description() string
- func (i MyFabulousOhNoError) Error() string
- func (i MyFabulousOhNoError) OhNo(message string, extra any, cause error, ...) (ohnoError error)
- func (i MyFabulousOhNoError) Package() string
- func (i MyFabulousOhNoError) String() string
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MyFabulousOhNoError ¶
type MyFabulousOhNoError int
We first define a custom type like the one below
Example (Check) ¶
This example demonstrates how an OhNoError can be checked directly against the enum. Here Foo() returns an OhNoError which is being compared with the code usage_with_ohno.Fatal which will match. You can also check one OhNoError with another directly but in that case the whole error should match.
package main import ( "errors" "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { err := Foo() if err != nil { if errors.Is(err, usage_with_ohno.Fatal) { fmt.Printf("oh no its fatal!!!\n\t%s", err.Error()) } if errors.Is(err, err) { fmt.Println() fmt.Println("they match !!!") } } }
Output: oh no its fatal!!! 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here} they match !!!
Example (ConvertToJoinError) ¶
There may be cases where you may get an error with deep nesting and when marshalling it into either text, json or yaml you may want to improve readability by flattening out the structure. To do that you can take any error of OhNoError type and then convert them OhNoJoinError type
package main import ( "encoding/json" "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { // Lets begin with fooErr which we now know has no nested errors fooErr := Foo() // Lets wrap it with one other error barErr := usage_with_ohno.Internal.OhNo( "this error wraps fooErr", "level-1 nesting", fooErr, // This is where we wrap sourceinfo.NoSourceInfo, time.Unix(300, 0).UTC(), time.DateTime, ) // Lets wrap barErr with one more error bazErr := usage_with_ohno.Unknown.OhNo( "this error wraps barErr", "level-2 nesting", barErr, sourceinfo.NoSourceInfo, time.Unix(600, 0).UTC(), time.DateTime, ) flattenedErr := ohno.ConvertToJoinError(bazErr) bazJson, err := json.MarshalIndent(bazErr, "", " ") if err != nil { fmt.Println(err.Error()) return } flattenedJson, err := json.MarshalIndent(flattenedErr, "", " ") if err != nil { fmt.Println(err.Error()) return } fmt.Println("error is wrapped so all nested errors will be indented") fmt.Println(bazErr.Error()) fmt.Println() fmt.Println("all nested errors are flattened, no indentation") fmt.Println(flattenedErr.Error()) fmt.Println() fmt.Println("----") fmt.Println() fmt.Print("json representation of nested error") fmt.Println(string(bazJson)) fmt.Println() fmt.Print("json representation of flattened error") fmt.Println(string(flattenedJson)) }
Output: error is wrapped so all nested errors will be indented 1970-01-01 00:10:00 [0x67]usage_with_ohno.Unknown: I don't know what happened, this error wraps barErr, level-2 nesting -> 1970-01-01 00:05:00 [0x66]usage_with_ohno.Internal: Its not you, its me :(, this error wraps fooErr, level-1 nesting -> 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here} all nested errors are flattened, no indentation 1970-01-01 00:10:00 [0x67]usage_with_ohno.Unknown: I don't know what happened, this error wraps barErr, level-2 nesting 1970-01-01 00:05:00 [0x66]usage_with_ohno.Internal: Its not you, its me :(, this error wraps fooErr, level-1 nesting 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here} ---- json representation of nested error{ "additional_info": "level-2 nesting", "caused_by": { "additional_info": "level-1 nesting", "caused_by": { "additional_info": { "BadStuff": "some data here" }, "source_information": { "file": "example_test.go", "function": "github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo", "line": 23 }, "package": "usage_with_ohno", "code": "0x6a", "name": "Fatal", "message": "something really bad happened", "description": "Help!!! Im dying!!!", "timestamp": "1970-01-01 00:00:00" }, "package": "usage_with_ohno", "code": "0x66", "name": "Internal", "message": "this error wraps fooErr", "description": "Its not you, its me :(", "timestamp": "1970-01-01 00:05:00" }, "package": "usage_with_ohno", "code": "0x67", "name": "Unknown", "message": "this error wraps barErr", "description": "I don't know what happened", "timestamp": "1970-01-01 00:10:00" } json representation of flattened error{ "errors": [ { "additional_info": "level-2 nesting", "package": "usage_with_ohno", "code": "0x67", "name": "Unknown", "message": "this error wraps barErr", "description": "I don't know what happened", "timestamp": "1970-01-01 00:10:00" }, { "additional_info": "level-1 nesting", "package": "usage_with_ohno", "code": "0x66", "name": "Internal", "message": "this error wraps fooErr", "description": "Its not you, its me :(", "timestamp": "1970-01-01 00:05:00" }, { "additional_info": { "BadStuff": "some data here" }, "source_information": { "file": "example_test.go", "function": "github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo", "line": 23 }, "package": "usage_with_ohno", "code": "0x6a", "name": "Fatal", "message": "something really bad happened", "description": "Help!!! Im dying!!!", "timestamp": "1970-01-01 00:00:00" } ] }
Example (Join) ¶
You can use the default errors.Join or use ohno.Join method to join multiple errors. The advantage of using ohno.Join is that it is friendly with json and yaml marshaling
package main import ( "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { // Lets take whatever error foo returns fooErr := Foo() // Now lets create our own error myErr := usage_with_ohno.Internal.OhNo( "something went wrong", // message string "some data", // extra any nil, // cause error sourceinfo.NoSourceInfo, // sourceInfoType sourceinfo.SourceInfoType time.Unix(300, 0).UTC(), // timestamp time.Time time.DateTime, // timestampLayout string ) // When printing the errors will be printed in the same order you've sent // them to ohno.Join joinErr := ohno.Join(myErr, fooErr) fmt.Println(joinErr.Error()) }
Output: 1970-01-01 00:05:00 [0x66]usage_with_ohno.Internal: Its not you, its me :(, something went wrong, some data 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here}
Example (Marshal) ¶
As a part of the structured representation goals of this package the OhNoError can be marshalled in json and yaml formats.
fooErr := Foo() fooJson, err := json.MarshalIndent(fooErr, "", " ") if err != nil { fmt.Println(err.Error()) return } fooYaml, err := yaml.Marshal(fooErr) if err != nil { fmt.Println(err.Error()) return } fmt.Println("json:") fmt.Println(string(fooJson)) fmt.Println() fmt.Println("yaml:") fmt.Println(string(fooYaml))
Output: json: { "additional_info": { "BadStuff": "some data here" }, "source_information": { "file": "example_test.go", "function": "github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo", "line": 23 }, "package": "usage_with_ohno", "code": "0x6a", "name": "Fatal", "message": "something really bad happened", "description": "Help!!! Im dying!!!", "timestamp": "1970-01-01 00:00:00" } yaml: additional_info: badstuff: some data here source_information: file: example_test.go function: github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo line: 23 package: usage_with_ohno code: "0x6a" name: Fatal message: something really bad happened description: Help!!! Im dying!!! timestamp: "1970-01-01 00:00:00"
Example (Switch) ¶
You can even directly use switch case here to check against multiple errors after converting it to OhNoError and using the embedded ErrorCode field.
package main import ( "errors" "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { err := Foo() prefix := "i don't know what this is" if err != nil { var ohNoErr *ohno.OhNoError if errors.As(err, &ohNoErr) { switch ohNoErr.ErrorCode { case usage_with_ohno.AlreadyExists: prefix = "well its there already" case usage_with_ohno.NotFound: prefix = "nah I didn't find it" case usage_with_ohno.Busy: prefix = "not now!!" case usage_with_ohno.Fatal: prefix = "oh no its fatal!!!" } } fmt.Printf("%s\n\t%s", prefix, err.Error()) } }
Output: oh no its fatal!!! 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here}
Example (Usage) ¶
In this example we are simply defining a function Foo() which can return an error which needs to printed to the console.
package main import ( "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { // We just print what ever foo returns fmt.Println(Foo().Error()) }
Output: 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here}
Example (WrapUnwrap) ¶
By default the OhNo method allows you wrap an error inside an OhNoError when creating one. This example shows you how to do it. Typically if you get any error from your dependencies and you want to wrap them into the error you wish to emit then you would use this feature.
package main import ( "errors" "fmt" "time" "github.com/A-0-5/ohno/examples/usage_with_ohno" "github.com/A-0-5/ohno/pkg/sourceinfo" ) // This is a function which returns an error of type [github.com/A-0-5/ohno/pkg/ohno.OhNoError] func Foo() error { return usage_with_ohno.Fatal.OhNo( "something really bad happened", struct{ BadStuff string }{"some data here"}, nil, sourceinfo.ShortFileAndLineWithFunc, time.Unix(0, 0).UTC(), time.DateTime, ) } func main() { // Let the error that Foo() returns be called fooErr fooErr := Foo() // Now we can wrap this inside another OhNoError. Let us use Unknown as a wrapper error for this. myError := usage_with_ohno.Unknown.OhNo( "Ive got no clue as to what happened", // message string 12345, // extra any - this can be anything , even nil if you don't want it to be there fooErr, // cause error - fooErr caused this error sourceinfo.NoSourceInfo, // sourceInfoType sourceinfo.SourceInfoType - I dont need the source information for this time.Unix(300, 0).UTC(), // timestamp time.Time - 1 Jan 1970 00:05 time.DateTime, // timestampLayout string - Date Time format ) // Let us print this error fmt.Println(myError.Error()) // Now lets unwrap this and see whats inside (we already know :P) causeOfMyError := errors.Unwrap(myError) // We already know that fooErr was wrapped inside myError, lets confirm if errors.Is(causeOfMyError, fooErr) { fmt.Println("causeOfMyError is fooErr") } // We can also see that its a Fatal error type if errors.Is(causeOfMyError, usage_with_ohno.Fatal) { fmt.Println("causeOfMyError is usage_with_ohno.Fatal") } }
Output: 1970-01-01 00:05:00 [0x67]usage_with_ohno.Unknown: I don't know what happened, Ive got no clue as to what happened, 12345 -> 1970-01-01 00:00:00 example_test.go:23 (github.com/A-0-5/ohno/examples/usage_with_ohno_test.Foo): [0x6a]usage_with_ohno.Fatal: Help!!! Im dying!!!, something really bad happened, {BadStuff:some data here} causeOfMyError is fooErr causeOfMyError is usage_with_ohno.Fatal
const ( NotFound MyFabulousOhNoError = 100 + iota // I didn't find what you were looking for! AlreadyExists // I have this already! Internal // Its not you, its me :( Unknown // I don't know what happened Busy // I'm busy rn, can we do this later? Fatal // Help!!! Im dying!!! )
Now here we define all the possible error values this package can return and run the command. (here formatbase=16 will make all the codes print in hex representation)
ohnogen -type=MyFabulousOhNoError -formatbase=16 -output=example_errors.go -ohno
As this example purely concentrates on using the enums directly without depending on the ohno package the -ohno flag is omitted
func (MyFabulousOhNoError) Code ¶
func (i MyFabulousOhNoError) Code() string
Returns the integer code string as per the format base provided
func (MyFabulousOhNoError) Description ¶
func (i MyFabulousOhNoError) Description() string
Returns the description string
func (MyFabulousOhNoError) Error ¶
func (i MyFabulousOhNoError) Error() string
Returns the error's string representation [CODE]PACKAGE_NAME.ERROR_NAME: DESCRIPTION
func (MyFabulousOhNoError) OhNo ¶
func (i MyFabulousOhNoError) OhNo(message string, extra any, cause error, sourceInfoType sourceinfo.SourceInfoType, timestamp time.Time, timestampLayout string) (ohnoError error)
Generate a new error of ohno.OhNoError type with the data provided timestamp is optional, empty timestampLayout will assume default timestamp of RFC3339Nano, if you do not want source information to be captured pass sourceinfo.NoSourceInfo for the sourceInfoType parameter.
func (MyFabulousOhNoError) Package ¶
func (i MyFabulousOhNoError) Package() string
Returns the package name
func (MyFabulousOhNoError) String ¶
func (i MyFabulousOhNoError) String() string
Returns the error name as string