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)
})
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.
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
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)
}
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.
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
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)
}
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.
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
}
})
}
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.
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.
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
}
}
}()
}