usage_with_ohno

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 2, 2024 License: BSD-3-Clause Imports: 4 Imported by: 0

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

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?
	Unauthorised                                   // You ain't got the creds to do this
	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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL