Manual instrumentation guide
You can manually send monitoring data to the WhaTap agent using the Go library. Example code is available at github.com/whatap/go-api-example.
Automatic instrumentation vs Manual instrumentation
- Automatic instrumentation (Recommended): Refer to Automatic instrumentation guide for automatic code insertion
- Manual instrumentation: Add the APIs described in this document directly to your code
Getting started
Install the Go API with the following command:
go get github.com/whatap/go-api@latest
Init, Shutdown
Basic structure for initializing and shutting down the monitoring module:
import "github.com/whatap/go-api/trace"
func main(){
trace.Init(nil)
defer trace.Shutdown()
...
}
Init function configuration options:
- Can be configured in
map[string]stringformat - Can also be configured in
whatap.conffile - Default TCP connection: 127.0.0.1:6600
m := make(map[string]string)
m["net_ipc_host"] = "127.0.0.1"
m["net_ipc_port"] = "6601"
trace.Init(m)
whatap.conf configuration:
accesskey={access key}
whatap.server.host={collection server IP address}
net_ipc_host=127.0.0.1
net_ipc_port=6600
Context management
The agent distinguishes transactions based on whatap context(trace.TraceCtx). Performance information outside transactions is ignored or only statistics are collected.
Creating transactions
var traceCtx *TraceCtx
traceCtx.Txid = keygen.Next()
ctx = context.WithValue(ctx, "whatap", traceCtx)
Transaction tracing
Web transaction tracing
http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)
})
Wrapping functions:
trace.Func(): Sets RequestURI as transaction nametrace.HandlerFunc(): Provides same functionality
General transaction tracing
func main() {
ctx := context.Background()
ctx, _ := trace.Start(ctx, "Custom Transaction")
...
trace.End(ctx, nil)
}
Transaction API
func Start(ctx context.Context, name string) (context.Context, error)
func End(ctx context.Context, err error) error
func StartWithRequest(r *http.Request) (context.Context, error)
func Step(ctx context.Context, title, message string, elapsed, value int) error
func HandlerFunc(handler func(http.ResponseWriter, *http.Request)) http.HandlerFunc
func Func(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request)
DB connection and SQL tracing
Limitations:
- SQL statement: Maximum 32KB
- Prepared parameters: Maximum 20, 256 bytes each
DB Connection tracing
import whatapsql "github.com/whatap/go-api/sql"
ctx, _ := trace.Start(context.Background(), "Trace Open DB")
defer trace.End(ctx, nil)
sqlCtx, _ := whatapsql.StartOpen(ctx, "id@tcp(x.x.x.x:3306)/test")
db, err := sql.Open("mysql", "id:pwd@tcp(x.x.x.x:3306)/test")
whatapsql.End(sqlCtx, err)
defer db.Close()
SQL Query tracing
query = "select id, subject from tbl_faq limit 10"
sqlCtx, _ = whatapsql.Start(ctx, "id:pwd@tcp(x.x.x.x:3306)/test", query)
rows, err := db.QueryContext(ctx, query)
whatapsql.End(sqlCtx, err)
Prepared Statement tracing
query = "select id, subject from tbl_faq where id = ? limit ?"
stmt, err := db.Prepare(query)
defer stmt.Close()
params := make([]interface{}, 0)
params = append(params, 8)
params = append(params, 1)
sqlCtx, _ := whatapsql.StartWithParamArray(ctx, "id:pwd@tcp(x.x.x.x:3306)/test", query, params)
rows, err := stmt.QueryContext(ctx, params...)
whatapsql.End(sqlCtx, err)
Using database/sql package
import (
_ "github.com/go-sql-driver/mysql"
"github.com/whatap/go-api/instrumentation/database/sql/whatapsql"
)
db, err := whatapsql.OpenContext(ctx, "mysql", dataSource)
defer db.Close()
if rows, err := db.QueryContext(ctx, query); err == nil {
...
}
SQL API
func Start(ctx context.Context, dbhost, sql string) (*SqlCtx, error)
func StartOpen(ctx context.Context, dbhost string) (*SqlCtx, error)
func End(sqlCtx *SqlCtx, err error) error
func StartWithParam(ctx context.Context, dbhost, sql, param ...interface{}) (*SqlCtx, error)
func StartWithParamArray(ctx context.Context, dbhost, sql string, param []interface{}) (*SqlCtx, error)
func Trace(ctx context.Context, dbhost, sql, param string, elapsed int, err error) error
HTTP request tracing
import "github.com/whatap/go-api/httc"
ctx, _ := trace.Start(context.Background(), "Trace Http Call")
defer trace.End(ctx, nil)
httpcCtx, _ := httpc.Start(ctx, callUrl)
resp, err := http.Get(callUrl)
if err == nil {
httpc.End(httpcCtx, resp.StatusCode, "", nil)
} else {
httpc.End(httpcCtx, 0, "", err)
}
HTTP Transport RoundTrip
import "github.com/whatap/go-api/instrumentation/net/http/whataphttp"
ctx, _ := trace.Start(context.Background(), "Http call")
defer trace.End(ctx, nil)
client := http.DefaultClient
client.Transport = whataphttp.NewRoundTrip(ctx, http.DefaultTransport)
resp, err := client.Get(callUrl)
defer resp.Body.Close()
HTTP API
func Start(ctx context.Context, url string) (*HttpcCtx, error)
func End(httpcCtx *HttpcCtx, status int, reason string, err error) error
func Trace(ctx context.Context, host string, port int, url string, elapsed int, status int, reason string, err error) error
Multi-transaction tracing (Distributed tracing)
Trace transactions associated with other agents or projects.
Header key values:
x-wtap-pox-wtap-mstx-wtap-sp1
Also supports OpenTrace's traceparent header.
Agent configuration
mtrace_enabled=true
mtrace_rate=100
Request Header processing
func UpdateMtrace(traceCtx *trace.TraceCtx, header http.Header)
trace.StartWithRequest internally calls this function.
ctx, traceCtx := trace.GetTraceContext(ctx)
if traceCtx != nil {
trace.UpdateMtrace(traceCtx, header)
}
Retrieving and adding Header information
func GetMTrace(ctx context.Context) http.Header
This function returns headers needed for distributed tracing:
headers := trace.GetMTrace(wCtx)
for key, _ := range headers {
req.Header.Set(key, headers.Get(key))
}