goagent
provides a set of instrumentation features for collecting relevant tracing data as well as secure an application by blocking requests selectively using Traceable features.
Setting up Go Agent can be done with a few lines:
import (
"github.com/Traceableai/goagent"
"github.com/Traceableai/goagent/config"
)
//...
func main() {
cfg := config.Load()
cfg.Tracing.ServiceName = config.String("myservice")
shutdown := goagent.Init(cfg)
defer shutdown()
}
Config values can be declared in config file, env variables or code. For further information about config check this section.
By default, goagent
includes the Traceable filter into the server instrumentation (e.g. HTTP server or GRPC server)
based on the configuration features.
To run Traceable filter we need to:
First compile the binary using the build tag traceable_filter
, for example:
go build -tags 'traceable_filter' -o /path-to-app/myapp
Then, copy the library into the same folder as the compiled binary:
curl -sSL https://raw.githubusercontent.com/Traceableai/goagent/main/filter/traceable/copy-library.sh | bash -s -- /path-to-app
The server instrumentation relies on the http.Handler
component of the server declarations.
import (
"net/http"
"github.com/gorilla/mux"
"github.com/Traceableai/goagent/instrumentation/net/traceablehttp"
)
func main() {
// ...
r := mux.NewRouter()
r.Handle("/foo/{bar}", traceablehttp.NewHandler(
fooHandler, // existing user handler
"/foo/{bar}", // name of the span generated for this handler
))
// ...
}
Filters allow users to filter requests based on URL, headers or body. Filters can be added in the handler declaration using the traceablehttp.WithFilter
option. Multiple filters can be added too by using filter.NewMultiFilter
and they will be run in sequence until a filter returns true (request is blocked), or all filters are run.
import "github.com/hypertrace/goagent/sdk/filter"
// ...
r.Handle("/foo/{bar}", traceablehttp.NewHandler(
fooHandler,
"/foo/{bar}",
traceablehttp.WithFilter(filter.NewMultiFilter(filter1, filter2)),
))
// ...
The client instrumentation relies on the http.Transport
component of the HTTP client in Go.
import (
"net/http"
"github.com/Traceableai/goagent/instrumentation/net/traceablehttp"
)
// ...
client := http.Client{
Transport: traceablehttp.NewTransport(
http.DefaultTransport,
),
}
req, _ := http.NewRequest("GET", "http://example.com", nil)
res, err := client.Do(req)
// ...
In terminal 1 run the client:
go run ./_examples/http-client/main.go
In terminal 2 run the server:
go run ./_examples/http-server/main.go
Gin server instrumentation relies on adding the traceablegin.Middleware
middleware to the gin server.
r := gin.Default()
cfg := config.Load()
cfg.ServiceName = config.String("http-gin-server")
flusher := goagent.Init(cfg)
defer flusher()
r.Use(traceablegin.Middleware())
To run an example gin server with the middleware:
go run ./_examples/gin-server/main.go
Then make a request to localhost:8080/ping
The server instrumentation relies on the grpc.UnaryServerInterceptor
component of the server declarations.
server := grpc.NewServer(
grpc.UnaryInterceptor(
traceablegrpc.UnaryServerInterceptor(),
),
)
Filters allow users to filter requests based on URL, headers or body. Filters can be added in the server interceptor declaration using the traceablegrpc.WithFilter
option. Multiple filters can be added too by using filter.NewMultiFilter
and they will be run in sequence until a filter returns true (request is blocked), or all filters are run.
import "github.com/hypertrace/goagent/sdk/filter"
// ...
grpc.UnaryInterceptor(
traceablegrpc.UnaryServerInterceptor(
traceablegrpc.WithFilter(filter.NewMultiFilter(filter1, filter2))
),
),
The client instrumentation relies on the http.Transport
component of the HTTP client in Go.
import (
// ...
traceablegrpc "github.com/Traceableai/goagent/instrumentation/google.golang.org/traceablegrpc"
"google.golang.org/grpc"
)
func main() {
// ...
conn, err := grpc.Dial(
address,
grpc.WithInsecure(),
grpc.WithBlock(),
grpc.WithUnaryInterceptor(
traceablegrpc.UnaryClientInterceptor(),
),
)
if err != nil {
log.Fatalf("could not dial: %v", err)
}
defer conn.Close()
client := pb.NewCustomClient(conn)
// ...
}
In terminal 1 run the client:
go run ./_examples/grpc-client/main.go
In terminal 2 run the server:
go run ./_examples/grpc-server/main.go