Skip to main content

Go Agent v0.1.12

Release date: 2022-08-02

Beta - update

The Alpine Linux is supported.

Installation guide

[whatap-agent.tar.gz]After downloading the file (https://s3.ap-northeast-2.amazonaws.com/repo.whatap.io/alpine/x86_64/whatap-agent.tar.gz), unzip the file based on the "/" directory. Create the monitoring file in the /usr/whatap/agent path.

wget https://s3.ap-northeast-2.amazonaws.com/repo.whatap.io/alpine/x86_64/whatap-agent.tar.gz
tar -xvzf whatap-agent.tar.gz -C /

Running the whatap-agent

/usr/whatap/agent/whatap-agent 
Default restart
Command start, stop, restart, version

## Checking the version
# /usr/whatap/agent/whatap-agent version
0.8.5.20201209

## Checking the execution
# ps -elf | grep whatap
103 root 0:05 ./whatap_agent_static -t=4

Supporting the github.com/go-chi/chi library

It traces the web transactions in the chi framework. Through the Use function, register and trace the middleware.

Installation guide

import (
"github.com/go-chi/chi"
"github.com/whatap/go-api/trace"
"github.com/whatap/go-api/instrumentation/github.com/go-chi/chi/whatapchi"
)

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

r := chi.NewRouter()

// Register the middleware of whatapchi.
r.Use(whatapchi.Middleware)

r.Get("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Response -", r.Response)
})

Example reference

Supporting the github.com/go-gorm/gorm library

It traces the DB connection and SQLs processed through the gorm v2 framework.

How to use the whatapgorm

Instead of the gorm.Open function, the whatapgorm.OpenWithContext function is used. The context to be passed must include whatap TraceCtx, and can be created through the Start function of the trace package.

Install guide
import (
"net/http"

"github.com/whatap/go-api/instrumentation/github.com/go-gorm/gorm/whatapgorm"
"github.com/whatap/go-api/trace"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)

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

http.HandleFunc("/InsertAndDelete", func(w http.ResponseWriter, r *http.Request) {
// Create the context.
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)

// Connect the DB through whatapgorm.
db, err := whatapgorm.OpenWithContext(sqlite.Open("test.db"), &gorm.Config{}, ctx)
if err != nil {
panic("Db connection failed.")
}

for i := 0; i < 100; i++ {
db.Create(&Product{Code: i, Price: i * 100})
}

db.Unscoped().Delete(&Product{}, "Code >= ? AND Code < ?", 0, 100)
})

_ = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

How to use the whatapsql

In addition to officially supported sqlite, mysql, postgres, and sqlserver, the gorm is compatible with the drivers written based on the dialect interface.

Related link: gorm driver

Install guide
import (
"net/http"
"github.com/whatap/go-api/instrumentation/database/sql/whatapsql"
"github.com/whatap/go-api/trace"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

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

http.HandleFunc("/WhatapDriverTest", func(w http.ResponseWriter, r *http.Request) {
// Create the context.
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)

// Create the DB connection via the whatapsql driver.
dbConn, err := whatapsql.OpenContext(ctx, "mysql", dataSource)

// Connect gorm through the created connection.
db, err := gorm.Open(mysql.New(mysql.Config{Conn: dbConn}), &gorm.Config{})
if err != nil {
panic("DB connection failed.")
}

for i := 0; i < 100; i++ {
db.Create(&Product{Code: i, Price: i * 100})
}
})

_ = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

Reference example

Supporting the github.com/jinzhu/gorm library

It traces the DB connection and SQLs processed through the gorm v1 framework.

How to use the whatapgorm

Instead of the gorm.Open function, the whatapgorm.OpenWithContext function is used. The context to be passed must include whatap TraceCtx, and can be created through the Start function of the trace package.

Install guide
import (
"net/http"

"github.com/whatap/go-api/instrumentation/github.com/go-gorm/gorm/whatapgorm"
"github.com/whatap/go-api/trace"
_ "github.com/mattn/go-sqlite3"
"github.com/jinzhu/gorm"
)

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

http.HandleFunc("/InsertAndDelete", func(w http.ResponseWriter, r *http.Request) {
// Create the context.
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)

// Connect the DB via whatapgorm.
db, err := whatapgorm.OpenWithContext(ctx, "sqlite3", "test.db")
defer db.Close()
if err != nil {
trace.Error(ctx, err)
panic("Gorm Open Fail")
}

for i := 0; i < 100; i++ {
db.Create(&Product{Code: i, Price: i * 100})
}

db.Unscoped().Delete(Product{}, "Code >= ? AND Code < ?", 0, 100)
})

_ = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

How to use the whatapsql

In addition to officially supported sqlite, mysql, postgres, and sqlserver, the gorm is compatible with the drivers written based on the dialect interface.

Related link: gorm driver

Install guide
import (
"net/http"
"github.com/whatap/go-api/instrumentation/database/sql/whatapsql"
"github.com/whatap/go-api/trace"
"github.com/jinzhu/gorm"
_ "github.com/go-sql-driver/mysql"
)

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

http.HandleFunc("/WhatapDriverTest", func(w http.ResponseWriter, r *http.Request) {
// Create the context.
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)

// Create the DB connection via the whatapsql driver.
var conn gorm.SQLCommon
var err error
conn, err = whatapsql.OpenContext(ctx, "mysql", dataSource)
if err != nil {
trace.Error(ctx, err)
panic("Whatapsql Open Fail")
}

// Connect gorm via the created connection.
db, err := gorm.Open("mysql", conn)
if err != nil {
trace.Error(ctx, err)
panic("Gorm Open Fail")
}
for i := 0; i < 100; i++ {
db.Create(&Product{Code: i, Price: i * 100})
}
})

_ = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

Reference example

Supporting the github.com/gomodule/redigo library

It traces commands passed to Redis via the redigo framework. Instead of redis.Dial, the whatapredigo.DialContext function is used.

Install guide
import (
"context"
"net/http"

"github.com/gomodule/redigo/redis"
"github.com/whatap/go-api/instrumentation/github.com/gomodule/redigo/whatapredigo"
"github.com/whatap/go-api/trace"
)

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

http.HandleFunc("/SetAndGetWithDialContext", func(w http.ResponseWriter, r *http.Request) {
// Create the context.
ctx, _ := trace.StartWithRequest(r)
defer trace.End(ctx, nil)

// Create the Redis connection via the whtapredigo.
conn, err := whatapredigo.DialContext(ctx, "tcp", "127.0.0.1:6379")
if err != nil {
trace.Error(ctx, err)
return
}
defer conn.Close()

_, err = conn.Do("SET", "DataKey", "DataValue")
if err != nil {
trace.Error(ctx, err)
return
}

data, err := redis.Bytes(conn.Do("GET", "DataKey"))
if err != nil {
trace.Error(ctx, err)
return
}
})
}

Reference example

Supporting the github.com/shopify/sarama library

It traces the kafka produce and consume events processed through the sarama framework.

Tracing the async producer

It traces the async producer data through the whatapsarama's interceptor. When generating the producer message, if CTX-related data is passed through metadata, it is connected to the multi-transaction.

Install guide
import (
"context"
"net/http"
"github.com/Shopify/sarama"
"github.com/whatap/go-api/instrumentation/github.com/Shopify/sarama/whatapsarama"
"github.com/whatap/go-api/trace"
)

func main() {
config := sarama.NewConfig()
brokers := []string{"127.0.0.1:9092"} //config kafka broker IP/Port

// Register the interrupt of whatapsarama in the config.
interceptor := whatapsarama.Interceptor{Brokers: brokers}
config.Producer.Interceptors = []sarama.ProducerInterceptor{&interceptor}

whatapConfig := make(map[string]string)
trace.Init(whatapConfig)
defer trace.Shutdown()

// The config is delivered upon prdoducer creation.
producer, err := sarama.NewAsyncProducer(brokers, config)
consumerOffset := sarama.OffsetOldest
if err != nil {
panic(err)
}
defer func() {
if err := producer.Close(); err != nil {
panic(err)
}
}()

http.HandleFunc("/AsyncProduceInput", func(w http.ResponseWriter, r *http.Request) {
ctx, _ := trace.StartWithRequest(r)
defer func() {
trace.End(ctx, nil)
}()
msg := &sarama.ProducerMessage{
Topic: "tmp-topic",
Key: sarama.StringEncoder("Data Key"),
Value: sarama.StringEncoder("Data Value"),
Metadata: trace.GetMTrace(ctx),
}
producer.Input() <- msg //error check

})

_ = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

Tracing the consumer

It traces the consumer data through the whatapsarama's interceptor. Based on the message delivered from the producer, it is connected to the multi-transaction.

Install guide
import (
"context"
"flag"
"fmt"
"net/http"
"text/template"

"github.com/Shopify/sarama"
"github.com/whatap/go-api/instrumentation/github.com/Shopify/sarama/whatapsarama"
"github.com/whatap/go-api/trace"
)

func main() {
config := sarama.NewConfig()
brokers := []string{"127.0.0.1:9092"} //config kafka broker IP/Port

// Register the interrupt of whatapsarama in the config.
interceptor := whatapsarama.Interceptor{Brokers: brokers}
config.Consumer.Interceptors = []sarama.ConsumerInterceptor{&interceptor}

// 1 transaction per consumption
// The config is delivered when creating a consumer.
consumer, err := sarama.NewConsumer(brokers, config)
topic := "tmp-topic"

partitions, _ := consumer.Partitions(topic)
consume, _ := consumer.ConsumePartition(topic, partitions[0], consumerOffset)

if consume == nil {
fmt.Println("consume nil")
return
}

go func() {
for {
select {
case msg := <-consume.Messages():
fmt.Println(msg)
case consumerError := <-consume.Errors():
fmt.Println("error", consumerError)
return
}
}
}()
}

Reference example