Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg committed Jun 1, 2023
1 parent 16faf01 commit 695e0f5
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 1 deletion.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
17 changes: 17 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: build

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0' # run "At 00:00 on Sunday"

# See https://github.com/cristalhq/.github/.github/workflows
jobs:
build:
uses: cristalhq/.github/.github/workflows/build.yml@v0.5.0

vuln:
uses: cristalhq/.github/.github/workflows/vuln.yml@v0.5.0
1 change: 1 addition & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Guide for errorx
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
# errorx
# errorx

[![build-img]][build-url]
[![pkg-img]][pkg-url]
[![version-img]][version-url]

TODO

## Rationale

TODO

## Features

* Simple and easy.
* Safe & fast.
* Tested.
* Dependency-free.

See [these docs][pkg-url] or [GUIDE.md](GUIDE.md) for more details.

## Install

Go version 1.18+

```
go get github.com/cristalhq/errorx
```

## Example

```go
```

See examples: [example_test.go](example_test.go).

## License

[MIT License](LICENSE).

[build-img]: https://github.com/cristalhq/errorx/workflows/build/badge.svg
[build-url]: https://github.com/cristalhq/errorx/actions
[pkg-img]: https://pkg.go.dev/badge/cristalhq/errorx
[pkg-url]: https://pkg.go.dev/github.com/cristalhq/errorx
[version-img]: https://img.shields.io/github/v/release/cristalhq/errorx
[version-url]: https://github.com/cristalhq/errorx/releases
60 changes: 60 additions & 0 deletions errorx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package errorx

import (
"errors"
"fmt"
"strings"
)

func New(text string) error {
if IsTracingEnabled() {
return &errorString{
s: text,
frame: caller(1),
}
}
return errors.New(text)
}

func Newf(format string, a ...any) error {
if IsTracingEnabled() && !strings.Contains(format, "%w") {
return &errorString{
s: fmt.Sprintf(format, a...),
frame: caller(1),
}
}
return fmt.Errorf(format, a...)
}

// Is is just [errors.Is].
func Is(err, target error) bool {
return errors.Is(err, target)
}

// As is just [errors.As].
func As(err error, target any) bool {
return errors.As(err, target)
}

func IsAny(err, target error, targets ...error) bool {
if errors.Is(err, target) {
return true
}

for _, t := range targets {
if errors.Is(err, t) {
return true
}
}
return false
}

// errorString same as [errors.errorString] but with a frame field.
type errorString struct {
s string
frame Frame
}

func (e *errorString) Error() string {
return e.s
}
51 changes: 51 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package errorx_test

import (
"fmt"
"os"

"github.com/cristalhq/errorx"
)

func ExampleNew() {
err := errorx.New("this is the error")
err2 := errorx.New("this is the error")

if err == err2 {
panic("should be different")
}

fmt.Println(err)
fmt.Println(err2)

// Output:
// this is the error
// this is the error
}

func ExampleNewf() {
err := errorx.Newf("this is the error, code: %d", 123)
err2 := errorx.Newf("this is the error, code: %d", 123)

if err == err2 {
panic("should be different")
}

fmt.Println(err)
fmt.Println(err2)

// Output:
// this is the error, code: 123
// this is the error, code: 123
}

func ExampleIsAny() {
err := os.ErrPermission

if errorx.IsAny(err, os.ErrNotExist, os.ErrPermission) {
fmt.Println("it's not DNS")
}

// Output:
// it's not DNS
}
22 changes: 22 additions & 0 deletions frame.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package errorx

import (
"runtime"
)

type Frame struct {
frames [3]uintptr
}

func (f Frame) Location() (function, file string, line int) {
frames := runtime.CallersFrames(f.frames[:])
if _, ok := frames.Next(); !ok {
return "", "", 0
}

fr, ok := frames.Next()
if !ok {
return "", "", 0
}
return fr.Function, fr.File, fr.Line
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/cristalhq/errorx

go 1.18
14 changes: 14 additions & 0 deletions trace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package errorx

import "sync/atomic"

var traceFlag int32

// IsTracingEnabled reports whether trace is attached to the errors.
func IsTracingEnabled() bool { return atomic.LoadInt32(&traceFlag) == 0 }

// EnableTrace collection for errors.
func EnableTrace() { atomic.StoreInt32(&traceFlag, 0) }

// DisableTrace collection for errors.
func DisableTrace() { atomic.StoreInt32(&traceFlag, 1) }
9 changes: 9 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package errorx

import "runtime"

func caller(skip int) Frame {
var s Frame
runtime.Callers(skip+1, s.frames[:])
return s
}

0 comments on commit 695e0f5

Please sign in to comment.