Go: Error handling and tracing with OpenCensus supported platforms
Bryan Sazon
Posted on July 15, 2019
errors
I want to share my drop-in replacement for github.com/pkg/errors
.
I created this package to help my current team view the details of my Stackdriver traces with Stackdriver logs.
- https://cloud.google.com/trace/docs/viewing-details
- https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
- https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntrySourceLocation
Goals
Add OpenCensus trace attributes when creating a new error.
Basic Usage
Drop-in replacement. Creating an error.
err := errors.New("msg") // Wrap .. Wrapf .. Errof ..
Creating an error with context useful for monitoring.
func main() {
_, span := trace.StartSpan(context.Background(), "ExampleNewT")
defer span.End()
err := errors.NewT(span, "error")
fmt.Println(err)
if erctx, ok := err.(errors.Error); ok {
fmt.Println(erctx.SourceLocation().Function)
fmt.Println(erctx.SourceLocation().File)
fmt.Println(erctx.SourceLocation().Line)
fmt.Println(erctx.TraceContext().TraceID)
fmt.Println(erctx.TraceContext().SpanID)
}
}
Output
main.main
/Users/jb/Golang/src/github.com/bzon/errors/examples/main.go
15
d2d2b126d0474947821106525e32b6e0
1644b4b9be26c929
How I use it
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/bzon/errors"
"github.com/go-kit/kit/log"
"go.opencensus.io/trace"
)
func main() {
var useStackDriver = flag.Bool("stack-driver", false, "Use stackdriver instead of jaeger.")
flag.Parse()
// logging
var logger log.Logger
{
logger = log.NewJSONLogger(log.NewSyncWriter(os.Stdout))
logger = log.With(logger, "ts", log.DefaultTimestamp, "caller", log.DefaultCaller)
}
// tracing
switch {
case *useStackDriver:
// stackdriver
sd, err := stackdriver.NewExporter(stackdriver.Options{
ProjectID: os.Getenv("GCP_PROJECT"),
})
if err != nil {
panic(fmt.Sprintf("Failed to create the stackdriver exporter: %v", err))
}
defer sd.Flush()
trace.RegisterExporter(sd)
default:
je, err := jaeger.NewExporter(jaeger.Options{
AgentEndpoint: "localhost:6831",
CollectorEndpoint: "http://localhost:14268/api/traces",
ServiceName: "erroring-service",
})
if err != nil {
panic(fmt.Sprintf("Failed to create the Jaeger exporter: %v", err))
}
trace.RegisterExporter(je)
}
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
for {
workerr := work(context.Background(), logger)
if ec, ok := workerr.(errors.Error); ok {
logger.Log(
"message", ec.Error(),
"logging.googleapis.com/spanId", ec.TraceContext().SpanID,
"logging.googleapis.com/trace", ec.TraceContext().TraceID,
"logging.googleapis.com/sourceLocation", ec.SourceLocation(),
)
}
time.Sleep(3 * time.Second)
}
}
func work(ctx context.Context, logger log.Logger) error {
_, span := trace.StartSpan(ctx, "work")
defer span.End()
// error with context
err := errors.NewT(span, "error")
return err
}
You can also see the source code of the example server in github.
Useful for logging error with tracing context.
$ go run main.go | jq '.'
{
"caller": "main.go:38",
"logging.googleapis.com/sourceLocation": {
"function": "main.work",
"file": "/Users/jb/Golang/src/github.com/bzon/errors/examples/main.go",
"line": 55
},
"logging.googleapis.com/spanId": "1eb9494ab1a7831c",
"logging.googleapis.com/trace": "e97499da53ef2a8fdf9681beddbe3d64",
"message": "error",
"ts": "2019-07-15T09:37:06.885078+02:00"
}
Automatic annotations will be applied in supported tracing platform for OpenCensus.
💖 💪 🙅 🚩
Bryan Sazon
Posted on July 15, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.