errorswithstack

package
v3.18.2 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2024 License: MIT Imports: 6 Imported by: 0

README

ErrorsWithStack Plugin

The errorswithstack plugin is a Goa v3 plugin that adds a stack trace to every original service error. This plugin depends on github.com/cockroachdb/errors/withstack.

Enabling the Plugin

To enable the plugin simply import as follows:

import (
  _ "github.com/tchssk/goaplugins/v3/errorswithstack"
  . "goa.design/goa/v3/dsl"
)

Effects on Code Generation

Enabling the plugin changes the behavior of the gen command of the goa tool.

The gen command output is modified as follows:

  1. All error initialization helper functions are modified to add a stack trace to the original service error using WithStackDepth().

    func MakeInternalError(err error) *goa.ServiceError {
    -	return goa.NewServiceError(err, "internal_error", false, false, true)
    +	return goa.NewServiceError(withstack.WithStackDepth(err, 1), "internal_error", false, false, true)
    }
    

Middleware

You can capture errors using the Goa endpoint middleware. The topmost caller can be extracted using GetOneLineSource():

func ErrorLogger(logger *log.Logger) func(goa.Endpoint) goa.Endpoint {
	return func(e goa.Endpoint) goa.Endpoint {
		return goa.Endpoint(func(ctx context.Context, req any) (any, error) {
			res, err := e(ctx, req)
			if err != nil {
				file, line, _, ok := withstack.GetOneLineSource(err)
				if ok {
					logger.Printf("%s:%d: %v", file, line, err) // file.go:15 something went wrong
				}
			}
			return res, err
		})
	}
}

or GetReportableStackTrace():

func ErrorLogger(logger *log.Logger) func(goa.Endpoint) goa.Endpoint {
	return func(e goa.Endpoint) goa.Endpoint {
		return goa.Endpoint(func(ctx context.Context, req any) (any, error) {
			res, err := e(ctx, req)
			if err != nil {
				if st := withstack.GetReportableStackTrace(errors.Unwrap(err)); st != nil {
					if len(st.Frames) >= 1 {
						frame := st.Frames[len(st.Frames)-1]
						logger.Printf("%s:%d: %v", frame.AbsPath, frame.Lineno, err) // /path/to/file.go:15 something went wrong
					}
				}
			}
			return res, err
		})
	}
}

The error's underlying concrete value is ServiceError. You can also create conditions by making type assertion:

func ErrorLogger(logger *log.Logger) func(goa.Endpoint) goa.Endpoint {
	return func(e goa.Endpoint) goa.Endpoint {
		return goa.Endpoint(func(ctx context.Context, req any) (any, error) {
			res, err := e(ctx, req)
			if err != nil {
				if serviceError, ok := err.(*goa.ServiceError); ok {
					if serviceError.Fault {
						file, line, _, ok := withstack.GetOneLineSource(err)
						if ok {
							logger.Printf("%s:%d: %v", file, line, err) // file.go:15 something went wrong
						}
					}
				}
			}
			return res, err
		})
	}
}

You can also report errors to Sentry using report.ReportError:

func ErrorReporter() func(goa.Endpoint) goa.Endpoint {
	return func(e goa.Endpoint) goa.Endpoint {
		return goa.Endpoint(func(ctx context.Context, req any) (any, error) {
			res, err := e(ctx, req)
			if err != nil {
				report.ReportError(err)
			}
			return res, err
		})
	}
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Generate

func Generate(genpkg string, roots []eval.Root, files []*codegen.File) ([]*codegen.File, error)

Types

This section is empty.

Jump to

Keyboard shortcuts

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