Skip to main content

API Guide

The example code in this document is available in the github.com/whatap/go-api-example repository.

Download

Download the package and the related dependencies.

go get github.com/whatap/go-api

Getting started

init, shutdown

Start the monitoring module by using the trace.Init() function. defer trace.Shutdown() makes sure that the monitoring ends.

Go
import "github.com/whatap/go-api/trace"

func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

...
}

func Init(m map[string]string)

This can be set in the initial stage of the application by declaring it in the form of map[string]string. Otherwise, more settings can be added in whatap.conf. The performance information can be sent to the WhaTap collection server only when TCP connection to the agent is established normally. It performs TCP communication via 127.0.0.1:6600 using the basic connection information.

To change the connection information, pass the settings to the Init function, or set them in the whatap.conf file and then restart the application.

Go
m := make(map[string]string)
m["net_ipc_host"] = "127.0.0.1"
m["net_ipc_port"] = "6601"

trace.Init(m)
whatap.conf
accesskey={access key}
whatap.server.host={collection server IP}
net_ipc_host=127.0.0.1
net_ipc_host=6600

Context

The agents collect performance data based on the transaction. The transactions are classified based on the context to which whatap context(trace.TraceCtx) belongs. The performance data that is not related to transactions is ignored or collected only as statistical data.

Generating transactions

The whatap context is generated by the Start and StartWithReqest functions of the go-api/trace module. Set the TraceCtx data with the whatap key in the context.

Go
var traceCtx *TraceCtx
traceCtx.Txid = keygen.Next()
ctx = context.WithValue(ctx, "whatap", traceCtx)

In APIs for transactions, SQLs, DBConnections, external HTTP requests, and general function tracing, the Context in which the TraceCtx object exists as the whatap key is required at startup.

Transaction tracing

It traces all transactions from web requests to responses, and traces transactions for normal work units. It consists of the startup and end functions. It is recognized as a single transaction, and you can see the detailed views on the hitmap widget and the statistical metrics such as TPS, response time, and average response time.

You can collect HTTP parameters and HTTP headers through the settings.

Web transaction trace

Go
http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)
}
  • trace.Func(), trace.HandlerFunc()

    • Function that wraps Handle and HandFunc of the net/http

    • Proceed with trace.StartWithRequest and trace.End in the same way.

    • The name of the web transaction is set to RequestURI.

  • trace.Step()

    It provides the function to output the strings delivered by the user to the profile data.

    Go
    http.HandleFunc("/wrapHandleFunc", trace.Func(func(w http.ResponseWriter, r *http.Request) {
    ...
    }))
    Go
    http.Handle("/wrapHandleFunc1", trace.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ...
    }))

General transaction trace

Go
func main() {
...

ctx := context.Background()
ctx, _ := trace.Start(ctx, "Custom Transaction")

...

trace.End(ctx, nil)

...
}

API

Go
func Start(ctx context.Context, name string) (context.Context, error)
Go
func End(ctx context.Context, err error) error
Go
func StartWithRequest(r *http.Request) (context.Context, error)
Go
func Step(ctx context.Context, title, message string, elapsed, value int) error
Go
func HandlerFunc(handler func(http.ResponseWriter, *http.Request)) http.HandlerFunc
Go
func Func(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request)

DB connection and SQL tracing

Execution times and errors can be collected by passing parameters for DB connection, SQL syntax, errors, and prepared statements to the API. SQL statements can be collected up to 32 KB. The parameters for SQL prepared statements are collected up to 20 and up to 256 bytes for each.

DB Connection

Go
import (
whatapsql "github.com/whatap/go-api/sql"
)

func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

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()
}
Go
import (
whatapsql "github.com/whatap/go-api/sql"
)

func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

ctx, _ := trace.Start(context.Background(), "Trace Query")
defer trace.End(ctx, nil)

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)
}
Go
import (
whatapsql "github.com/whatap/go-api/sql"
)

func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

ctx, _ := trace.Start(context.Background(), "Trace Prepared Statement")
defer trace.End(ctx, nil)

// Create Prepared Statement
query = "select id, subject from tbl_faq where id = ? limit ?"
stmt, err := db.Prepare(query)
if err != nil {
return
}
defer stmt.Close()

params := make([]interface{}, 0)
params = append(params, 8)
params = append(params, 1)

sqlCtx, _ := whatapsql.StartWithParamArray(ctx, "id:pwd(x.x.x.x:3306)/test", query, params)
rows, err := stmt.QueryContext(ctx, params...)
whatapsql.End(sqlCtx, err)


sqlCtx, _ = whatapsql.StartWithParam(ctx, "id:pwd(x.x.x.x:3306)/test", query, params...)
rows, err := stmt.QueryContext(ctx, params...)
whatapsql.End(sqlCtx, err)
}

Database/SQL package configuration

Use the whatapsql.OpenContext function instead of the sql.Open function of the database/sql package. It is recommended to use the functions that pass the contexts, such as PrepareContext, QueryContext, and ExecContext. The context to be delivered must have the whatap TraceCtx data through trace.Start().

Go

import (
_ "github.com/go-sql-driver/mysql"
"github.com/whatap/go-api/instrumentation/database/sql/whatapsql"
)

func main() {
config := make(map[string]string)
trace.Init(config)
defer trace.Shutdown()

// The whatap TraceCtx is generated inside whataphttp.Func.
http.HandleFunc("/query", whataphttp.Func(func(w http.ResponseWriter, r *http.Request){
ctx := r.Context()

// Use the WhaTap Driver. It passes the contexts that have TraceCtx.
db, err := whatapsql.OpenContext(ctx, "mysql", dataSource)
if err != nil {
fmt.Println("Error whatapsql.Open ", err)
return
}
defer db.Close()

...
query := "select id, subject from tbl_faq limit 10"

// It passes the contexts that have TraceCtx.
if rows, err := db.QueryContext(ctx, query); err == nil {
...
}
}
...
}

API

Go
func Start(ctx context.Context, dbhost, sql string) (*SqlCtx, error)
Go
func StartOpen(ctx context.Context, dbhost string) (*SqlCtx, error)
Go
func End(sqlCtx *SqlCtx, err error) error
Go
func StartWithParam(ctx context.Context, dbhost, sql, param ...interface{}) (*SqlCtx, error)
Go
func StartWithParamArray(ctx context.Context, dbhost, sql string, param []interface{}) (*SqlCtx, error)
Go
func Trace(ctx context.Context, dbhost, sql, param string, elapsed int, err error) error

Tracing the HTTP requests

Go
import (
"github.com/whatap/go-api/httc"
)

func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

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

You can set up the RoundTrip.

Go
import (
"github.com/whatap/go-api/instrumentation/net/http/whataphttp"
)
func main() {
config := make(map[string]string)
trace.Init(config)
defer trace.Shutdown()

ctx, _ := trace.Start(context.Background(), "Http call")
defer trace.End(ctx, nil)

callUrl := "http://aaa.com/xxx"
client := http.DefaultClient
// Use WhaTap RoundTrip. It passes the contexts that have TraceCtx.
client.Transport = whataphttp.NewRoundTrip(ctx, http.DefaultTransport)
resp, err := client.Get(callUrl)
if err != nil {
...
}
defer resp.Body.Close()
...
}

API

Go
func Start(ctx context.Context, url string) (*HttpcCtx, error)
Go
func End(httpcCtx *HttpcCtx, status int, reason string, err error) error
Go
func Trace(ctx context.Context, host string, port int, url string, elapsed int, status int, reason string, err error) error

Multi-Transacrtion Trace

Multi-transaction refers to transactions associated with other agents or projects. Tracking calls between application services registered in the WhaTap project is called multi-transaction tracing.

Note

WhaTap tracks multi-transactions using three HTTP header keys (x-wtap-po, x-wtap-mst, x-wtap-sp1). If cross-link tracking of HTTP transactions passing through a gateway which is not working, please check the HTTP header conditions.

Supports TraceContext for open-source tracing (traceparent header tracing).

Configuring the agent

Set the followin options on agent coniguration file(whatap.conf) for multi-transaction tracing.

whatap.conf
# Activation option, Default: false
mtrace_enabled=true

# Sampling rate, Default: 10
mtrace_rate=100

The trace.StartWithRequest function internally includes calls to the UpdateMtrace function. If you are not using the trace.StartWithRequest function, analyze the received header information by directly calling it.

Go
// func GetTraceContext(ctx context.Context) (context.Context, *TraceCtx)
// if v := ctx.Value("whatap"); v != nil {
// return ctx, v.(*TraceCtx)
// }
ctx, traceCtx := trace.GetTraceContext(ctx);
if traceCtx != nil {
trace.UpdateMtrace(traceCtx, header)
}
Note

Connect to trace.Start fucntion:

Go
func Start(ctx context.Context, name string) (context.Context, error) {
ctx, traceCtx := NewTraceContext(ctx)
traceCtx.Name = name
traceCtx.StartTime = dateutil.SystemNow()
// update multi trace info
UpdateMtrace(traceCtx, http.Header{})

...

Conenct to trace.StartWithRequest function:

Go
func StartWithRequest(r *http.Request) (context.Context, error) {
ctx, traceCtx := NewTraceContext(r.Context())
traceCtx.Name = r.RequestURI
traceCtx.StartTime = dateutil.SystemNow()
// update multi trace info
UpdateMtrace(traceCtx, r.Header)

...

Adding the header information when connection HTTP

When establishing an external HTTP connection, add header information for tracing to the Request headers.

Go
import (
"github.com/whatap/go-api/trace"
)

func GetMTrace(ctx context.Context) http.Header

The following function retrieves the headers required for distributed tracing. The returned headers should be added to external Request requests. The context must include the trace.TraceContext information of the "whatap" item. This information is added internally when using the trace.Start, StartWithRequest, and StartWithContext functions.

Example code
headers := trace.GetMTrace(wCtx)
for key, _ := range headers {
// req *http.Request
// The Add function is also available.
req.Header.Set(key, headers.Get(key))
}

Adding header automatically

In the WhaTap transport (RoundTrip), there is already code that utilizes GetMTrace internally. Enabling the option will automatically add the header information.

Example code
import (
"net/http"
"github.com/whatap/go-api/instrumentation/net/http/whataphttp"
)

...

//client := http.DefaultClient
client := http.Client{
Timeout: timeout,
}
client.Transport = whataphttp.NewRoundTrip(ctx, http.DefaultTransport)
if resp, err := client.Get(callUrl); err == nil {
...
}

The following is sample codes with multiple transprot. The context must include the trace.TraceContext information of the "whatap" item.

Exmple code
import (
"net/http"
"github.com/whatap/go-api/instrumentation/net/http/whataphttp"
)

...

client := http.DefaultClient
client.Transport = NewAccessLogRoundTrip(whataphttp.NewRoundTrip(ctx, http.DefaultTransport))

...

Function tracing

This API measures the execution time of the user function or desired section. API can be set before or after execution of the function.

Go
import (
"github.com/whatap/go-api/method"
)
func main(){
trace.Init(nil)
//It must be executed before closing the app.
defer trace.Shutdown()

ctx, _ := trace.Start(context.Background(), "Trace Method")
defer trace.End(ctx, nil)

getUser(ctx)
}

func getUser(ctx context.Context) {
methodCtx, _ := method.Start(ctx, "getUser")
defer method.End(methodCtx, nil)
time.Sleep(time.Duration(1) * time.Second)
}

API

Go
func Start(ctx context.Context, name string) (*MethodCtx, error)
Go
func End(methodCtx *MethodCtx, err error) error
Go
func Trace(ctx context.Context, name string, elapsed int, err error) error