Skip to content
Open
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
39 changes: 0 additions & 39 deletions docs/developing.md

This file was deleted.

4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ require (
github.com/dave/dst v0.27.3
github.com/stretchr/testify v1.11.1
github.com/urfave/cli/v3 v3.4.1
golang.org/x/mod v0.28.0
golang.org/x/mod v0.25.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/tools v0.13.0 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM=
github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
4 changes: 2 additions & 2 deletions tool/cmd/cmd_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ var commandGo = cli.Command{

err = setup.Setup(ctx)
if err != nil {
return ex.Errorf(err, "failed to build with toolexec with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to build with toolexec with exit code %d", exitCodeFailure)
}

err = setup.BuildWithToolexec(ctx, cmd.Args().Slice())
if err != nil {
return ex.Errorf(err, "failed to build with toolexec with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to build with toolexec with exit code %d", exitCodeFailure)
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion tool/cmd/cmd_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var commandSetup = cli.Command{
Action: func(ctx context.Context, _ *cli.Command) error {
err := setup.Setup(ctx)
if err != nil {
return ex.Errorf(err, "failed to setup with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to setup with exit code %d", exitCodeFailure)
}
return nil
},
Expand Down
2 changes: 1 addition & 1 deletion tool/cmd/cmd_toolexec.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var commandToolexec = cli.Command{
Action: func(ctx context.Context, cmd *cli.Command) error {
err := instrument.Toolexec(ctx, cmd.Args().Slice())
if err != nil {
return ex.Errorf(err, "failed to run toolexec with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to run toolexec with exit code %d", exitCodeFailure)
}
return nil
},
Expand Down
10 changes: 5 additions & 5 deletions tool/cmd/cmd_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,32 @@ var commandVersion = cli.Command{
Action: func(_ context.Context, cmd *cli.Command) error {
_, err := fmt.Fprintf(cmd.Writer, "otel version %s", Version)
if err != nil {
return ex.Errorf(err, "failed to print version with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to print version with exit code %d", exitCodeFailure)
}

if CommitHash != "unknown" {
_, err = fmt.Fprintf(cmd.Writer, "+%s", CommitHash)
if err != nil {
return ex.Errorf(err, "failed to print version with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to print version with exit code %d", exitCodeFailure)
}
}

if BuildTime != "unknown" {
_, err = fmt.Fprintf(cmd.Writer, " (%s)", BuildTime)
if err != nil {
return ex.Errorf(err, "failed to print version with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to print version with exit code %d", exitCodeFailure)
}
}

_, err = fmt.Fprint(cmd.Writer, "\n")
if err != nil {
return ex.Errorf(err, "failed to print version with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to print version with exit code %d", exitCodeFailure)
}

if cmd.Bool("verbose") {
_, err = fmt.Fprintf(cmd.Writer, "%s\n", runtime.Version())
if err != nil {
return ex.Errorf(err, "failed to print version with exit code %d", exitCodeFailure)
return ex.Wrapf(err, "failed to print version with exit code %d", exitCodeFailure)
}
}

Expand Down
4 changes: 2 additions & 2 deletions tool/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ func initLogger(ctx context.Context, cmd *cli.Command) (context.Context, error)
buildTempDir := cmd.String("work-dir")
err := os.MkdirAll(buildTempDir, 0o755)
if err != nil {
return ctx, ex.Errorf(err, "failed to create work directory %q", buildTempDir)
return ctx, ex.Wrapf(err, "failed to create work directory %q", buildTempDir)
}

logFilename := filepath.Join(buildTempDir, debugLogFilename)
writer, err := os.OpenFile(logFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
if err != nil {
return ctx, ex.Errorf(err, "failed to open log file %q", buildTempDir)
return ctx, ex.Wrapf(err, "failed to open log file %q", buildTempDir)
}

// Create a custom handler with shorter time format
Expand Down
4 changes: 2 additions & 2 deletions tool/data/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var dataFs embed.FS
func ListEmbedFiles() ([]string, error) {
rules, err := dataFs.ReadDir(".")
if err != nil {
return nil, ex.Errorf(err, "failed to read directory")
return nil, ex.Wrapf(err, "failed to read directory")
}

var ruleFiles []string
Expand All @@ -32,7 +32,7 @@ func ListEmbedFiles() ([]string, error) {
func ReadEmbedFile(path string) ([]byte, error) {
bs, err := dataFs.ReadFile(path)
if err != nil {
return nil, ex.Errorf(err, "failed to read file")
return nil, ex.Wrapf(err, "failed to read file")
}
return bs, nil
}
148 changes: 148 additions & 0 deletions tool/ex/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ex

import (
"errors"
"fmt"
"os"
"runtime"
"strings"
)

// -----------------------------------------------------------------------------
// Extended Error Handling with Stack Traces
//
// These APIs provide an error handling framework that allows errors to carry
// stack trace information.
//
// The core usage pattern is to create an error with a stack trace at its origin
// This allows the error to be propagated up the call stack by simply returning
// it (return err), without needing to be re-wrapped at each level.
//
// While the simplest pattern is to return the error directly, you can also use
// Wrap or Wrapf at any point in the call chain to add more contextual information.
// This is useful when an intermediate function has valuable context that is not
// available at the error's origin.
//
// Create and wrap an error:
//
// 1. To wrap an existing error from a standard or third-party library, use Wrap
// or Wrapf. This attaches a stack trace to the original error.
//
// Example:
// if err := some_lib.DoSomething(); err != nil {
// return ex.Wrapf(err, "additional context for the error")
// }
// if err := some_lib.DoSomething(); err != nil {
// return ex.Wrap(err)
// }
//
// 2. To create a new error from scratch, use Newf. This generates a new
// error with a stack trace at the point of creation.
//
// Example:
// if unexpected {
// return ex.Newf("unexpected error")
// }
//
// Terminate the program:
//
// Use Fatalf or Fatal to exit the program with an stackful error. It will print
// the error message and stack trace to the standard error output.

const numSkipFrame = 4 // skip the Errorf/Fatalf caller

// stackfulError represents an error with stack trace information
type stackfulError struct {
message []string
frame []string
wrapped error
}

func (e *stackfulError) Error() string { return strings.Join(e.message, "\n") }
func (e *stackfulError) Unwrap() error { return e.wrapped }

func getFrames() []string {
const initFrames = 30
frameList := make([]string, 0)
pcs := make([]uintptr, initFrames)
n := runtime.Callers(numSkipFrame, pcs)
if n == 0 {
return frameList
}
pcs = pcs[:n]
frames := runtime.CallersFrames(pcs)
cnt := 0
for {
frame, more := frames.Next()
if !more {
break
}
const prefix = "github.com/open-telemetry/opentelemetry-go-compile-instrumentation"
fnName := strings.TrimPrefix(frame.Function, prefix)
f := fmt.Sprintf("[%d]%s:%d %s", cnt, frame.File, frame.Line, fnName)
frameList = append(frameList, f)
cnt++
}
return frameList
}

// wrapOrCreate wraps an error with stack trace information and a formatted message
// If the error is already a stackfulError, it will be decorated with the new message.
// Otherwise, a new stackfulError will be created.
func wrapOrCreate(previousErr error, format string, args ...any) error {
se := &stackfulError{}
if errors.As(previousErr, &se) {
attach := fmt.Sprintf(format, args...)
if attach != "" {
se.message = append(se.message, attach)
}
return previousErr
}
// User defined error message + existing error message
errMsg := fmt.Sprintf(format, args...)
if previousErr != nil {
errMsg = fmt.Sprintf("%s: %s", errMsg, previousErr.Error())
}
e := &stackfulError{
message: []string{errMsg},
frame: getFrames(),
wrapped: previousErr,
}
return e
}

func Wrap(previousErr error) error {
return wrapOrCreate(previousErr, "")
}

func Wrapf(previousErr error, format string, args ...any) error {
return wrapOrCreate(previousErr, format, args...)
}

func Newf(format string, args ...any) error {
return wrapOrCreate(nil, format, args...)
}

func Fatalf(format string, args ...any) {
Fatal(Newf(format, args...))
}

func Fatal(err error) {
if err == nil {
panic("Fatal error: unknown")
}
e := &stackfulError{}
if errors.As(err, &e) {
em := ""
for i, m := range e.message {
em += fmt.Sprintf("[%d] %s\n", i, m)
}
msg := fmt.Sprintf("Error:\n%s\nStack:\n%s", em, strings.Join(e.frame, "\n"))
_, _ = fmt.Fprint(os.Stderr, msg)
os.Exit(1)
}
panic(err)
}
26 changes: 26 additions & 0 deletions tool/ex/ex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ex

import (
"errors"
"testing"

"github.com/stretchr/testify/require"
)

func TestError(t *testing.T) {
err := Newf("a")
err = Wrapf(err, "b")
err = Wrap(Wrap(Wrap(err))) // make no sense
require.Contains(t, err.Error(), "a")
require.Contains(t, err.Error(), "b")

err = errors.New("c")
err = Wrapf(err, "d")
err = Wrapf(err, "e")
err = Wrap(Wrap(Wrap(err))) // make no sense
require.Contains(t, err.Error(), "c")
require.Contains(t, err.Error(), "d")
}
Loading
Loading