Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds linters and Github Actions #2

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Test & Lint
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
strategy:
matrix:
go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x]
os: [ubuntu-latest, macos-latest, windows-latest]
name: tests
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
- name: Run tests
run: go test ./...
golangci:
strategy:
matrix:
go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x]
os: [ubuntu-latest]
name: lint
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
22 changes: 22 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
run:
concurency: 4
deadline: 2m
issues-exit-code: 1
tests: false

output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true

linters:
enable-all: true
fast: false

issues:
exclude-use-default: false
max-issues-per-linter: 100
max-same-issues: 4
new: false

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@ func main() {
fmt.Printf("%v", err)
}

// output
// output.
// bar(1, aerrors_wrap): foo(1): errors in foo
```
51 changes: 29 additions & 22 deletions aerror.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
// This package adds async errors handling support in GO. See the README for
// more details.
// Package aerrors adds async errors handling support in GO. See the README for more details.
package aerrors

import (
"fmt"
)

var defaultErrorChanLen = 10

// AsyncError queues your added errors in chan and handle them by provided handler method.
// It may be started and stopped and run your func in a panic-safe goroutine.
type AsyncError struct {
logger Logger
add chan error
stop chan struct{}
baseError error
handler ErrorHandler
errorChanLen int
errorChan chan error
logger Logger
add chan error
stop chan struct{}
baseError error
handler ErrorHandler
errorChan chan error
}

// ErrorHandler is an interface for defining error handler
// ErrorHandler is an interface for defining error handler.
type ErrorHandler interface {
HandleError(err error)
}
Expand All @@ -47,34 +43,44 @@ type ErrorHandler interface {
//
// See "aerrors.With*" to modify the default behavior.
func New(opts ...Option) *AsyncError {
const defaultErrorChanLen = 10

a := &AsyncError{
add: make(chan error),
stop: make(chan struct{}),
logger: DefaultLogger,
errorChan: make(chan error, defaultErrorChanLen),
logger: nil,
handler: nil,
baseError: nil,
}

for _, opt := range opts {
opt(a)
}

if a.logger == nil {
a.logger = createDefaultLogger()
}

return a
}

// Add puts your error in queue to handle. It blocks if we reached chan length
// Add puts your error in queue to handle. It blocks if we reached chan length.
func (e *AsyncError) Add(err error) {
e.errorChan <- err
}

// AddAsync puts your error in queue in goroutine. It not blocks when we reached chan length
// AddAsync puts your error in queue in goroutine. It not blocks when we reached chan length.
func (e *AsyncError) AddAsync(err error) {
go e.Add(err)
}

// Stop handle errors
// Stop handle errors.
func (e *AsyncError) Stop() {
e.stop <- struct{}{}
}

// StartHandle starts handling errors
// StartHandle starts handling errors.
func (e *AsyncError) StartHandle() {
go e.start()
}
Expand All @@ -87,29 +93,30 @@ func (e *AsyncError) start() {

case <-e.stop:
e.logger.Info("stop")

return
}
}
}

// Wrap your error
func Wrap(errp *error, format string, args ...interface{}) {
// Wrap your error.
func Wrap(errp *error, format string, args ...interface{}) { // nolint: goprintffuncname
if errp != nil && *errp != nil {
s := fmt.Sprintf(format, args...)
*errp = fmt.Errorf("%s: %w", s, *errp)
}
}

// PanicToError recovers panic and creates an error from it
// PanicToError recovers panic and creates an error from it.
func (e *AsyncError) PanicToError() {
if p := recover(); p != nil {
err := fmt.Errorf("%v", p)
err := fmt.Errorf("%v", p) //nolint: goerr113
Wrap(&err, "recoverToError()")
e.errorChan <- err
}
}

// Go runs your function in panic-safe goroutine
// Go runs your function in panic-safe goroutine.
func (e *AsyncError) Go(f func()) {
go func() {
defer e.PanicToError()
Expand Down
18 changes: 13 additions & 5 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import (
"strings"
)

// DefaultLogger is used if none is specified.
var DefaultLogger Logger = PrintfLogger(log.New(os.Stdout, "aerrors: ", log.LstdFlags))

// Logger is the interface used in this package for logging, so that any backend
// can be plugged in. It is a subset of the github.com/go-logr/logr interface.
type Logger interface {
Expand All @@ -18,6 +15,10 @@ type Logger interface {
Error(err error, msg string, keysAndValues ...interface{})
}

// DefaultLogger is used if none is specified.
func createDefaultLogger() Logger {
Copy link
Owner

@hanagantig hanagantig Jun 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this way we will create multiple logger structs that will lead to different mutexes in logger atomic methods

return PrintfLogger(log.New(os.Stdout, "aerrors: ", log.LstdFlags))
}

// PrintfLogger wraps a Printf-based logger (such as the standard library "log")
// into an implementation of the Logger interface which logs errors only.
Expand All @@ -39,24 +40,31 @@ func (pl printfLogger) Info(msg string, keysAndValues ...interface{}) {
}

func (pl printfLogger) Error(err error, msg string, keysAndValues ...interface{}) {
const BaseLength = 2

pl.logger.Printf(
formatString(len(keysAndValues)+2),
formatString(len(keysAndValues)+BaseLength),
append([]interface{}{msg, "error", err}, keysAndValues...)...)
}

// formatString returns a logfmt-like format string for the number of
// key/values.
func formatString(numKeysAndValues int) string {
var sb strings.Builder

sb.WriteString("%s")

if numKeysAndValues > 0 {
sb.WriteString(", ")
}

for i := 0; i < numKeysAndValues/2; i++ {
if i > 0 {
sb.WriteString(", ")
}

sb.WriteString("%v=%v")
}

return sb.String()
}
}