Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
APP_KEY=JzLRl2YHe1Ec7MCGqkAJ4byaF08uKLfs
APP_DEBUG=true
29 changes: 14 additions & 15 deletions debug/stack_trace_brispot.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package debug
import (
"fmt"
"runtime"
"slices"
"strings"
)

Expand All @@ -22,34 +23,32 @@ func GetStackTraceOnDebug(pick ...int) string {
// May be used when just want to get the stack trace without caring the debug
// state.
func GetStackTraceInString(pick ...int) string {
stack := make([]uintptr, 2<<6) // 128
length := runtime.Callers(0, stack) // skip no frames
stack := make([]uintptr, 2<<6)
length := runtime.Callers(0, stack)

var pickAll bool
// set default to capture the first found line
if len(pick) < 1 {
pickAll = true
}

trackPicked := 1
var allStackTrace strings.Builder
var traces []string
var seenFiles []string
for i := 0; i < length; i++ {
funcPtr := runtime.FuncForPC(stack[i])
file, line := funcPtr.FileLine(stack[i])
if strings.Contains(file, "/app/") {

s := fmt.Sprintf("%s:%d\n", file, line)
// capture the matched pick
if !pickAll && trackPicked == pick[0] {
return s
s := fmt.Sprintf("[%s:%d]", file, line)
if !slices.Contains(seenFiles, file) {
seenFiles = append(seenFiles, file)
if !pickAll && trackPicked == pick[0] {
return s
}
traces = append(traces, s)
trackPicked++
}

allStackTrace.WriteString(s)

trackPicked++

}
}

return allStackTrace.String()
return strings.Join(traces, " ")
}
19 changes: 19 additions & 0 deletions mocking/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package mocking

import "errors"

const (
ErrExpectedNetwork = "called error expected network"
ErrExpectedInfra = "called error expected infra"
)

func ProduceSampleError(errs ...error) error {
var errMsg string
if len(errs) > 0 {
for _, err := range errs {
errMsg += err.Error() + "\n"
}
return errors.New(errMsg)
}
return errors.New(ErrExpectedNetwork)
}
18 changes: 10 additions & 8 deletions stderr/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ var debugDepthLevel atomic.Int32
func errWithDebug(code string, msg string, httpCode int, metadata ...string) error {
e := err{code: code, msg: msg, httpCode: httpCode, metadata: metadata}

switch debugDepthLevel.Load() {
case -1:
e.stackTrc = debug.GetStackTraceOnDebug()
case 0: // the default, set to 1 so that at least it can print one line
e.stackTrc = debug.GetStackTraceOnDebug(1)
default:
e.stackTrc = debug.GetStackTraceOnDebug(int(debugDepthLevel.Load()))
}
//switch debugDepthLevel.Load() {
//case -1:
// e.stackTrc = debug.GetStackTraceOnDebug()
//case 0: // the default, set to 1 so that at least it can print one line
// e.stackTrc = debug.GetStackTraceOnDebug(1)
//default:
// e.stackTrc = debug.GetStackTraceOnDebug(int(debugDepthLevel.Load()))
//}

e.stackTrc = debug.GetStackTraceOnDebug()

return e
}
Expand Down
23 changes: 22 additions & 1 deletion stderr/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,28 @@ func (e err) Error() string {
//
// Each value can be retrieved by helper func such as GetCode, GetMsg, GetMeta.
func Err(code string, msg string, httpCode int) error {
return errWithDebug(code, msg, httpCode)
switch code {
case ERROR_CODE_ACCESS_PERMISSION:
return ErrPermission(msg)
case ERROR_CODE_DATA_NOT_FOUND:
return ErrDataNotFound()
case ERROR_CODE_INVALID_RULE:
return ErrInvRule(msg)
case ERROR_CODE_PARAMETER:
return ErrParam(msg)
case ERROR_CODE_WAITING_STATUS:
return ErrWaiting(msg)
case ERROR_CODE_THIRD_PARTY:
return ErrThirdParty(msg)
case ERROR_CODE_UNSUPPORTED:
return ErrUnsupported(msg)
case ERROR_CODE_INVALID_HEADER:
return ErrInvHeader(msg)
case ERROR_CODE_SYSTEM:
return ErrRuntime(msg)
default:
return ErrRuntime(msg)
}
}

// ErrValidation error in validation, it's not recommended to be used directly.
Expand Down
13 changes: 13 additions & 0 deletions stdresp/standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package stdresp

import (
"github.com/goravel/framework/contracts/http"
"github.com/spotlibs/go-lib/ctx"
"github.com/spotlibs/go-lib/log"
"github.com/spotlibs/go-lib/stderr"
)

Expand All @@ -25,6 +27,17 @@ func Resp(c http.Context, code, desc string, opts ...StdOpt) http.Response {
for _, opt := range opts {
opt(&res)
}

// Auto Logging Error
if res.ResponseCode == stderr.ERROR_CODE_SYSTEM {
mt := ctx.Get(c) // Retrieve X-Request-Id
log.Runtime(c).Error(log.Map{
"code": res.ResponseCode,
"message": res.ResponseDesc,
"requestID": mt.ReqId,
})
}

return c.Response().Json(res.httpCode, res)
}

Expand Down
90 changes: 90 additions & 0 deletions tests/mocking/error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package mocking_test

import (
"errors"
"strings"
"testing"

"github.com/spotlibs/go-lib/mocking"
"github.com/stretchr/testify/assert"
)

func TestProduceSampleError_NoArgs(t *testing.T) {
err := mocking.ProduceSampleError()

assert.Error(t, err)
assert.Equal(t, mocking.ErrExpectedNetwork, err.Error())
}

func TestProduceSampleError_SingleError(t *testing.T) {
inputErr := errors.New("single error")
err := mocking.ProduceSampleError(inputErr)

assert.Error(t, err)
assert.Contains(t, err.Error(), "single error")
}

func TestProduceSampleError_MultipleErrors(t *testing.T) {
err1 := errors.New("error one")
err2 := errors.New("error two")
err3 := errors.New("error three")

err := mocking.ProduceSampleError(err1, err2, err3)

assert.Error(t, err)
assert.Contains(t, err.Error(), "error one")
assert.Contains(t, err.Error(), "error two")
assert.Contains(t, err.Error(), "error three")
}

func TestProduceSampleError_WithNewlines(t *testing.T) {
err1 := errors.New("first")
err2 := errors.New("second")

err := mocking.ProduceSampleError(err1, err2)

lines := strings.Split(err.Error(), "\n")
assert.True(t, len(lines) >= 2)
}

func TestProduceSampleError_InfraError(t *testing.T) {
infraErr := errors.New(mocking.ErrExpectedInfra)
err := mocking.ProduceSampleError(infraErr)

assert.Error(t, err)
assert.Contains(t, err.Error(), mocking.ErrExpectedInfra)
}

func TestProduceSampleError_NetworkError(t *testing.T) {
networkErr := errors.New(mocking.ErrExpectedNetwork)
err := mocking.ProduceSampleError(networkErr)

assert.Error(t, err)
assert.Contains(t, err.Error(), mocking.ErrExpectedNetwork)
}

func TestProduceSampleError_EmptySlice(t *testing.T) {
err := mocking.ProduceSampleError([]error{}...)

assert.Error(t, err)
assert.Equal(t, mocking.ErrExpectedNetwork, err.Error())
}

func TestProduceSampleError_MixedErrors(t *testing.T) {
err1 := errors.New("database error")
err2 := errors.New("network timeout")
err3 := errors.New("invalid input")

err := mocking.ProduceSampleError(err1, err2, err3)

assert.Error(t, err)
errStr := err.Error()
assert.Contains(t, errStr, "database error")
assert.Contains(t, errStr, "network timeout")
assert.Contains(t, errStr, "invalid input")
}

func TestConstants(t *testing.T) {
assert.Equal(t, "called error expected network", mocking.ErrExpectedNetwork)
assert.Equal(t, "called error expected infra", mocking.ErrExpectedInfra)
}
4 changes: 2 additions & 2 deletions tests/stderr/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func TestErr(t *testing.T) {
err := stderr.Err("77", "oops", 200)

// assert the code
if stderr.GetCode(err) != "77" {
if stderr.GetCode(err) != "99" {
t.Errorf("expect %s, got %s", "77", stderr.GetCode(err))
}
// assert the message
Expand All @@ -25,7 +25,7 @@ func TestErr(t *testing.T) {

func TestErr_Error(t *testing.T) {
err := stderr.Err("77", "oops", 200)
if err.Error() != "77 oops" {
if err.Error() != "99 oops" { // -> Map to ErrRuntime, for code except stdCode
t.Errorf("expect %s, got %s", "77 oops", err.Error())
}
}
Expand Down