本文へスキップ

ユーザー定義計測

高度な機能

このドキュメントは上級ユーザー向けの内容です。ほとんどの場合、基本使用法設定ガイドだけで十分です。

whatap-go-instの基本計測で処理されない場合、ユーザー定義計測ルールを追加できます。

5つの計測方法

方法説明主な使用事例
add新しいファイル/関数を作成ヘルパー関数を追加
inject関数内部にコードを挿入すべての関数にtraceを追加
replace関数呼び出しを置換sql.Openwhatapsql.Open
hook関数呼び出しの前後にコードレガシーコード計測
transformパターン変換 (高度)複雑な変換

実行順序: add → inject → replace → hook → transform

基本設定構造

# .whatap/config.yaml
custom:
add: [] # 新しいファイル/関数を作成
inject: [] # 関数定義内部にコードを挿入
replace: [] # 関数呼び出しを置換
hook: [] # 関数呼び出しの前後にコードを挿入
transform: [] # コードパターン -> テンプレート変換

いつ使用しますか?

次のような場合、ユーザー定義計測が必要です。

  • 社内共通ライブラリにモニタリングを追加
  • サポートしていないフレームワークを計測
  • レガシーコードに直接修正せずにモニタリングを追加
  • 特定の関数のみを選択的に計測

add - 新しいファイル/関数を作成

ヘルパー関数やラッパーファイルを作成します。後でreplaceで使用できます。

基本使用

custom:
add:
- package: "myapp/helper" # 対象パッケージ
file: "whatap_helper.go" # 作成するファイル
content: |
package helper

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

func WrapQuery(ctx context.Context, query string) string {
ctx = trace.StartMethod(ctx, "WrapQuery")
defer trace.EndMethod(ctx, nil)
return query
}

変換結果

// 生成されたファイル: myapp/helper/whatap_helper.go
package helper

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

func WrapQuery(ctx context.Context, query string) string {
ctx = trace.StartMethod(ctx, "WrapQuery")
defer trace.EndMethod(ctx, nil)
return query
}
その他の例

テンプレートファイルの使用

custom:
add:
- package: "myapp/db"
file: "whatap_db.go"
content_file: "templates/db-helper.go.tmpl" # 外部テンプレートファイル

既存ファイルに関数を追加

custom:
add:
- package: "myapp/service"
file: "service.go" # 既存ファイル
append: true # ファイル末尾に追加
content: |
func traceMethod(ctx context.Context, name string) (context.Context, func()) {
return trace.StartMethod(ctx, name), func() { trace.EndMethod(ctx, nil) }
}

add + replace組み合わせ

custom:
# Step 1: ヘルパー関数を作成
add:
- package: "myapp/db"
file: "whatap_wrapper.go"
content: |
package db

func TracedQuery(ctx context.Context, sql string) (*Result, error) {
ctx = trace.StartMethod(ctx, "db.query")
defer trace.EndMethod(ctx, nil)
return OriginalQuery(sql)
}

# Step 2: 元の関数呼び出しをヘルパーに置換
replace:
- package: "myapp/db"
function: "Query"
with: "TracedQuery"

inject - 関数定義内部にコードを挿入

関数本文の開始/終了にコードを挿入します。

制限事項
  • 現在のモジュールのユーザー定義関数のみを対象に指定できます
  • Go標準ライブラリや外部パッケージの関数は対象に指定できません

基本使用

custom:
inject:
- package: "myapp/service" # Go importパス
function: "*" # 関数名 (* = 全体)
start: |
ctx = trace.StartMethod(ctx)
defer trace.EndMethod(ctx, err)
imports:
- "github.com/whatap/go-api/trace"

変換結果

// 変更前
func ProcessOrder(ctx context.Context) error {
// ビジネスロジック
}

// 変更後
func ProcessOrder(ctx context.Context) error {
ctx = trace.StartMethod(ctx) // <- start挿入
defer trace.EndMethod(ctx, err) // <- start挿入
// ビジネスロジック
}
deferパターン推奨

関数の途中にreturnがある場合、endの代わりにstartでdeferパターンを使用してください。

その他の例

特定の関数のみを対象

custom:
inject:
- package: "myapp/service"
function: "ProcessOrder" # 特定の関数名
start: |
ctx = trace.StartMethod(ctx, "ProcessOrder")
defer trace.EndMethod(ctx, nil)
imports:
- "github.com/whatap/go-api/trace"

replace - 関数呼び出しを置換

関数呼び出しを別の関数に置換します。

基本使用

custom:
replace:
- package: "database/sql"
function: "Open"
with: "whatapsql.Open"
imports:
- "github.com/whatap/go-api/instrumentation/database/sql/whatapsql"

変換結果

// 変更前
db, err := sql.Open("mysql", dsn)

// 変更後
db, err := whatapsql.Open("mysql", dsn)
その他の例

複数の関数を置換

custom:
replace:
- package: "database/sql"
function: "Open"
with: "whatapsql.Open"
imports:
- "github.com/whatap/go-api/instrumentation/database/sql/whatapsql"

- package: "github.com/jmoiron/sqlx"
function: "Connect"
with: "whatapsqlx.Connect"
imports:
- "github.com/whatap/go-api/instrumentation/github.com/jmoiron/sqlx/whatapsqlx"

hook - 関数呼び出しの前後にコードを挿入

関数呼び出しの前後にコードを挿入します。

ノート

beforeのみまたはafterのみを使用できます。

基本使用

custom:
hook:
- package: "mycompany/mydb"
function: "Query"
before: "ctx, span := trace.Start(ctx, \"db.query\")"
after: "span.End()"
imports:
- "github.com/whatap/go-api/trace"

変換結果

// 変更前
result, err := mydb.Query(sql)

// 変更後
ctx, span := trace.Start(ctx, "db.query") // <- before挿入
result, err := mydb.Query(sql)
span.End() // <- after挿入
その他の例

beforeのみ使用

custom:
hook:
- package: "mycompany/cache"
function: "Get"
before: "log.Printf(\"cache.Get called: %s\", key)"
imports:
- "log"

transform - コードパターンを変換

複雑なコードパターンをテンプレートで変換します。最も柔軟な方式です。

基本使用: ミドルウェアを追加

custom:
transform:
- package: "github.com/gin-gonic/gin"
function: "Default"
template: |
{{.Original}}
{{.Var}}.Use(whatapgin.Middleware())
imports:
- "github.com/whatap/go-api/instrumentation/github.com/gin-gonic/gin/whatapgin"

変換結果:

// 変更前
r := gin.Default()

// 変更後
r := gin.Default()
r.Use(whatapgin.Middleware())

高度な使用: クロージャーでラップ

custom:
transform:
- package: "github.com/aerospike/aerospike-client-go"
function: "NewClient"
template: |
func() (*as.Client, error) {
ctx, done := whatapsql.Start(context.Background(), "aerospike")
defer done()
return {{.Original}}
}()
imports:
- "context"
- "github.com/whatap/go-api/instrumentation/database/sql/whatapsql"

変換結果:

// 変更前
client, err := as.NewClient(policy, hosts...)

// 変更後
client, err := func() (*as.Client, error) {
ctx, done := whatapsql.Start(context.Background(), "aerospike")
defer done()
return as.NewClient(policy, hosts...)
}()
その他の例

HTTPクライアントラッピング

custom:
transform:
- package: "net/http"
function: "Get"
template: |
func() (*http.Response, error) {
ctx, done := httpc.Start(context.Background(), {{.Arg0}})
defer done()
return {{.Original}}
}()
imports:
- "context"
- "github.com/whatap/go-api/httpc"

テンプレート変数

transformで使用できるテンプレート変数です。

変数説明
{{.Original}}マッチした元のコードgin.Default()
{{.Var}}割り当てられた変数名r (r := ...から)
{{.Args}}関数全体の引数policy, hosts...
{{.Arg0}}, {{.Arg1}}個別の引数最初、2番目の引数
{{.FuncName}}関数名Default
{{.PkgName}}パッケージ名gin

使用例

custom:
transform:
- package: "mycompany/db"
function: "Query"
template: |
func() (*Result, error) {
ctx := trace.StartMethod(context.Background(), "{{.PkgName}}.{{.FuncName}}")
defer trace.EndMethod(ctx, nil)
return {{.Original}}
}()

変換結果:

// 変更前
result, err := db.Query("SELECT * FROM users")

// 変更後
result, err := func() (*Result, error) {
ctx := trace.StartMethod(context.Background(), "db.Query")
defer trace.EndMethod(ctx, nil)
return db.Query("SELECT * FROM users")
}()

実践例

例1: 内部ライブラリを計測

社内共通ライブラリにモニタリングを追加します。

# .whatap/config.yaml
custom:
# すべてのサービス関数にトレーシングを追加
inject:
- package: "mycompany/service"
function: "*"
start: |
ctx, span := trace.Start(ctx, "service")
defer span.End()
imports:
- "github.com/whatap/go-api/trace"

# 内部DBライブラリを置換
replace:
- package: "mycompany/db"
function: "Connect"
with: "whatapsql.Open"
imports:
- "github.com/whatap/go-api/instrumentation/database/sql/whatapsql"

例2: レガシーコードを計測

直接修正が難しいレガシーコードにモニタリングを追加します。

custom:
# レガシーHTTPクライアント呼び出しにトレーシングを追加
hook:
- package: "legacy/httpclient"
function: "Do"
before: |
ctx, span := httpc.Start(ctx, req.URL.String())
after: |
span.End()
imports:
- "github.com/whatap/go-api/httpc"

# レガシーキャッシュ呼び出しをログ記録
hook:
- package: "legacy/cache"
function: "Get"
before: |
startTime := time.Now()
after: |
trace.Step(ctx, "cache.Get", time.Since(startTime).Milliseconds(), nil)
imports:
- "time"
- "github.com/whatap/go-api/trace"

例3: カスタムミドルウェア

独自のミドルウェアを自動的に追加します。

custom:
# ヘルパーミドルウェアを作成
add:
- package: "myapp/middleware"
file: "whatap_middleware.go"
content: |
package middleware

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

func CustomTracing() gin.HandlerFunc {
return func(c *gin.Context) {
ctx := trace.Start(c.Request.Context(), c.Request.URL.Path)
c.Request = c.Request.WithContext(ctx)
defer trace.End(ctx, nil)
c.Next()
}
}

# Ginルーターにカスタムミドルウェアを追加
transform:
- package: "github.com/gin-gonic/gin"
function: "Default"
template: |
{{.Original}}
{{.Var}}.Use(middleware.CustomTracing())
imports:
- "myapp/middleware"

例4: 条件付き計測

特定の条件でのみ計測を有効化します。

custom:
transform:
- package: "mycompany/db"
function: "Query"
template: |
func() (*Result, error) {
if os.Getenv("WHATAP_ENABLED") == "true" {
ctx, done := whatapsql.Start(context.Background(), "db.query")
defer done()
}
return {{.Original}}
}()
imports:
- "os"
- "context"
- "github.com/whatap/go-api/instrumentation/database/sql/whatapsql"