- 重要な情報
- はじめに
- 用語集
- ガイド
- エージェント
- インテグレーション
- OpenTelemetry
- 開発者
- API
- CoScreen
- アプリ内
- Service Management
- インフラストラクチャー
- アプリケーションパフォーマンス
- 継続的インテグレーション
- ログ管理
- セキュリティ
- UX モニタリング
- 管理
このチュートリアルでは、ホスト上にインストールされたサンプル Go アプリケーションでトレースを有効にするための手順を説明します。このシナリオでは、アプリケーションと同じホスト上に Datadog Agent をインストールします。
コンテナ内またはクラウドインフラストラクチャーのアプリケーション、コンテナ内の Agent、異なる言語で書かれたアプリケーションなど、その他のシナリオについては、その他のトレース有効化のチュートリアルを参照してください。
Go の一般的なトレース設定ドキュメントについては、Go アプリケーションのトレースを参照してください。
sudo
を使用する際にルート権限を持つ物理または仮想の Linux ホスト。このホストには以下の要件があります。Datadog Agent をマシンにインストールしていない場合は、Integrations > Agent にアクセスし、お使いの OS を選択してください。例えば、ほとんどの Linux プラットフォームでは、<YOUR_API_KEY>
を Datadog API キーに置き換えて、以下のスクリプトを実行することで Agent をインストールすることができます。
DD_AGENT_MAJOR_VERSION=7 DD_API_KEY=<YOUR_API_KEY> DD_SITE="datadoghq.com" bash -c "$(curl -L https://install.datadoghq.com/scripts/install_script.sh)"
datadoghq.com
以外の Datadog サイトにデータを送信するには、DD_SITE
環境変数を Datadog サイトに置き換えてください。
Events > Explorer を開き、オプションで Datadog
ソースファセットでフィルタリングし、ホストへの Agent インストールを確認するイベントを探して、Agent が実行されており、Datadog にデータを送信していることを確認します。
次に、トレースするためのサンプルアプリケーションをインストールします。このチュートリアルのコードサンプルは github.com/DataDog/apm-tutorial-golang.git で見ることができます。以下を実行することで git リポジトリの複製を行います。
git clone https://github.com/DataDog/apm-tutorial-golang.git
次のコマンドを使用して、サンプルアプリケーションをビルドします。初めて実行するときは、このコマンドに時間がかかるかもしれません。
make runNotes
サンプルの notes
アプリケーションは、インメモリデータベースにデータを保存する基本的な REST API です。curl
を使っていくつかの API リクエストを送信します。
curl localhost:8080/notes
[]
を返しますcurl -X POST 'localhost:8080/notes?desc=hello'
hello
という説明と 1
という ID 値を追加します。{"id":1,"description":"hello"}
を返します。curl localhost:8080/notes/1
id
の値が 1
であるノートを返します: {"id":1,"description":"hello"}
curl -X POST 'localhost:8080/notes?desc=otherNote'
otherNote
という説明と 2
という ID 値を追加します。{"id":2,"description":"otherNote"}
を返します。curl localhost:8080/notes
[{"id":1,"description":"hello"},{"id";2,"description":"otherNote"}]
さらに API コールを実行し、アプリケーションのアクションを確認します。終了したら、以下のコマンドを実行して、アプリケーションを終了します。
make exitNotes
次に、Go トレーサーをインストールします。apm-tutorial-golang
ディレクトリから、以下を実行します。
go get gopkg.in/DataDog/dd-trace-go.v1/ddtrace
トレーシングライブラリが go.mod
に追加されたので、トレーシングのサポートを有効にします。
apm-tutorial-golang/cmd/notes/main.go
の以下のインポートのコメントを解除します。
cmd/notes/main.go
sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql"
chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"fmt"
インポートを変更します。
_ "github.com/mattn/go-sqlite3"
to:
"github.com/mattn/go-sqlite3"
main()
関数で、以下の行のコメントを解除します。
cmd/notes/main.go
tracer.Start()
defer tracer.Stop()
cmd/notes/main.go
client = httptrace.WrapClient(client, httptrace.RTWithResourceNamer(func(req *http.Request) string {
return fmt.Sprintf("%s %s", req.Method, req.URL.Path)
}))
cmd/notes/main.go
r.Use(chitrace.Middleware(chitrace.WithServiceName("notes")))
setupDB()
で、以下の行のコメントを解除します。
cmd/notes/main.go
sqltrace.Register("sqlite3", &sqlite3.SQLiteDriver{}, sqltrace.WithServiceName("db"))
db, err := sqltrace.Open("sqlite3", "file::memory:?cache=shared")
次の行をコメントアウトします。
cmd/notes/main.go
db, err := sql.Open("sqlite3", "file::memory:?cache=shared")
これらの変更を行ったら、以下を実行します。
go mod tidy
トレースの生成と収集を開始するには、make runNotes
で再度アプリケーションを起動します。
再びアプリケーションにリクエストを送るには、curl
を使用します。
curl localhost:8080/notes
[]
curl -X POST 'localhost:8080/notes?desc=hello'
{"id":1,"description":"hello"}
curl localhost:8080/notes/1
{"id":1,"description":"hello"}
curl localhost:8080/notes
[{"id":1,"description":"hello"}]
しばらく待って、Datadog の UI を見てみてください。APM > Traces に移動します。Traces リストには、次のように表示されます。
データベース (db
) と notes
アプリのエントリがあります。トレースリストには、すべてのスパン、いつ開始したか、どのリソースがスパンで追跡されたか、どれくらいの時間がかかったか、が表示されます。
もし、トレースが表示されない場合は、Traces Search フィールドのフィルターをクリアしてください (使用していない ENV
などの環境変数にフィルターをかけている場合があります)。
Traces ページで、POST /notes
トレースをクリックすると、各スパンにかかった時間や、あるスパンが完了する前に他のスパンが発生したことを示すフレームグラフが表示されます。グラフの上部にあるバーは、前の画面で選択したスパンです (この場合、ノートアプリケーションへの最初のエントリポイントです)。
バーの幅は、それが完了するまでにかかった時間を示します。低い深さのバーは、高い深さのバーの寿命の間に完了するスパンを表します。
POST
トレースのフレームグラフは次のようになります。
GET /notes
トレースは次のようになります。
トレーシングライブラリは、Datadog に送信するテレメトリーにタグを追加するように構成することができます。タグは、データをグループ化し、フィルターをかけ、ダッシュボードやグラフで有意義に表示するのに役立ちます。タグを追加するためには、アプリケーションを実行する際に環境変数を指定します。プロジェクトの Makefile
には、環境変数 DD_ENV
、DD_SERVICE
、DD_VERSION
が含まれており、これらは統合サービスタグ付けを有効にするように設定されています。
Makefile
run: build
DD_TRACE_SAMPLE_RATE=1 DD_SERVICE=notes DD_ENV=dev DD_VERSION=0.0.1 ./cmd/notes/notes &
Makefile
では DD_TRACE_SAMPLE_RATE
環境変数に 1
を設定し、これは 100% のサンプルレートを表しています。100% のサンプルレートは、このチュートリアルの目的のために、ノートサービスに対するすべてのリクエストが Datadog バックエンドに送信され、分析および表示されることを保証します。実際の本番環境や大量生産環境では、これほど高いレートを指定することはないでしょう。アプリケーションのこの変数で高いサンプルレートを設定すると、Agent の構成がオーバーライドされ、非常に大量のデータが Datadog に送信されることになります。ほとんどのユースケースでは、Agent が自動的にサンプリングレートを決定するようにします。利用可能な構成オプションの詳細については、Go トレーシングライブラリの構成を参照してください。
Datadog には Go 用に完全にサポートされたライブラリがいくつかあり、コードに実装することで自動トレーシングが可能になります。cmd/notes/main.go
ファイルでは、go-chi
、sql
、http
ライブラリが対応する Datadog ライブラリ (それぞれ chitrace
、sqltrace
、httptrace
) にエイリアスされているのが確認できます。
main.go
import (
...
sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql"
chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
...
)
cmd/notes/main.go
では、Datadog ライブラリは WithServiceName
オプションで初期化されます。例えば、chitrace
ライブラリは以下のように初期化されます。
main.go
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(chitrace.Middleware(chitrace.WithServiceName("notes")))
r.Mount("/", nr.Register())
chitrace.WithServiceName("notes")
を使用すると、ライブラリによってトレースされるすべての要素がサービス名 notes
に該当することを保証します。
main.go
ファイルには、これら各ライブラリの実装例がより多く含まれています。ライブラリの拡張機能については、Go 互換性要件を参照してください。
コードがサポートされているライブラリに該当しない場合、スパンを手動で作成することができます。
notes/notesController.go
の makeSpanMiddleware
関数の周りのコメントを削除してください。この関数は、リクエストを指定された名前のスパンでラップするミドルウェアを生成します。この関数を使用するには、以下の行をコメントアウトしてください。
notes/notesController.go
r.Get("/notes", nr.GetAllNotes) // GET /notes
r.Post("/notes", nr.CreateNote) // POST /notes
r.Get("/notes/{noteID}", nr.GetNoteByID) // GET /notes/123
r.Put("/notes/{noteID}", nr.UpdateNoteByID) // PUT /notes/123
r.Delete("/notes/{noteID}", nr.DeleteNoteByID) // DELETE /notes/123
以下の行の周りのコメントを削除します。
notes/notesController.go
r.Get("/notes", makeSpanMiddleware("GetAllNotes", nr.GetAllNotes)) // GET /notes
r.Post("/notes", makeSpanMiddleware("CreateNote", nr.CreateNote)) // POST /notes
r.Get("/notes/{noteID}", makeSpanMiddleware("GetNote", nr.GetNoteByID)) // GET /notes/123
r.Put("/notes/{noteID}", makeSpanMiddleware("UpdateNote", nr.UpdateNoteByID)) // PUT /notes/123
r.Delete("/notes/{noteID}", makeSpanMiddleware("DeleteNote", nr.DeleteNoteByID)) // DELETE /notes/123
また、以下のインポート周りのコメントも削除してください。
notes/notesController.go
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
サンプルアプリケーションには、カスタムトレースの例がいくつかあります。ここでは、さらにいくつかの例を紹介します。これらのスパンを有効にするには、コメントを削除してください。
doLongRunningProcess
関数は、親コンテキストから子スパンを作成します。
notes/notesHelper.go
func doLongRunningProcess(ctx context.Context) {
childSpan, ctx := tracer.StartSpanFromContext(ctx, "traceMethod1")
childSpan.SetTag(ext.ResourceName, "NotesHelper.doLongRunningProcess")
defer childSpan.Finish()
time.Sleep(300 * time.Millisecond)
log.Println("Hello from the long running process in Notes")
privateMethod1(ctx)
}
privateMethod1
関数は、コンテキストから完全に独立したサービスを作成することを示します。
notes/notesHelper.go
func privateMethod1(ctx context.Context) {
childSpan, _ := tracer.StartSpanFromContext(ctx, "manualSpan1",
tracer.SpanType("web"),
tracer.ServiceName("noteshelper"),
)
childSpan.SetTag(ext.ResourceName, "privateMethod1")
defer childSpan.Finish()
time.Sleep(30 * time.Millisecond)
log.Println("Hello from the custom privateMethod1 in Notes")
}
以下のインポートのコメントを解除します。
notes/notesHelper.go
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
make runNotes
でアプリケーションを起動し、再度 curl
コマンドを実行して、先ほど構成したカスタムスパンやトレースを観測します。
curl localhost:8080/notes
[]
curl -X POST 'localhost:8080/notes?desc=hello'
{"id":1,"description":"hello"}
curl localhost:8080/notes/1
{"id":1,"description":"hello"}
curl localhost:8080/notes
[{"id":1,"description":"hello"}]
カスタムトレースの詳細については、Go カスタムインスツルメンテーションを参照してください。
単一のアプリケーションをトレースすることは素晴らしいスタートですが、トレースの本当の価値は、リクエストがサービスを通じてどのように流れるかを見ることです。これは、_分散型トレーシング_と呼ばれています。
サンプルプロジェクトには calendar
という 2 番目のアプリケーションが含まれており、呼び出されるたびにランダムな日付を返します。ノートアプリケーションの POST
エンドポイントには、add_date
という名前の 2 つ目のクエリパラメーターがあります。このパラメータが y
に設定されると、ノートアプリケーションはカレンダーアプリケーションを呼び出して、ノートに追加する日付を取得します。
カレンダーアプリケーションでトレースを有効にするには、cmd/calendar/main.go
の以下の行のコメントを解除します。
cmd/calendar/main.go
chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
cmd/calendar/main.go
tracer.Start()
defer tracer.Stop()
cmd/calendar/main.go
r.Use(chitrace.Middleware(chitrace.WithServiceName("calendar")))
ノートアプリケーションがまだ実行されている場合は、make exitNotes
を使用して停止させます。
make run
を実行して、サンプルアプリケーションを起動します。
add_date
パラメーターを指定して、POST リクエストを送信します。
curl -X POST 'localhost:8080/notes?desc=hello_again&add_date=y'
トレースエクスプローラーで、この最新の notes
トレースをクリックすると、2 つのサービス間の分散型トレーシングが表示されます。
複数のアプリケーションからのインタラクションを組み合わせたフレームグラフです。
go-chi
ライブラリを通じて chi
ルーターが処理します。makeSpanMiddleware
関数によって手動でトレースされた createNote
関数です。この関数は、HTTP リクエストのコンテキストからスパンを作成します。http
ライブラリと main.go
ファイルで初期化されたクライアントを使用して、ノートアプリケーションから送信されたリクエストです。この GET リクエストは、カレンダーアプリケーションに送信されます。カレンダーアプリケーションのスパンは、別のサービスであるため、青色で表示されます。go-chi
ルーターが GET リクエストを処理し、GetDate
関数は GET リクエストの下にある独自のスパンで手動でトレースされます。db
呼び出しは、サポートされている sql
ライブラリからの独自のサービスです。GET /Calendar
リクエストと同じレベルに表示されますが、これはどちらも親スパンの CreateNote
から呼び出されるからです。もし、期待通りのトレースが受信できない場合は、Go トレーサーのでデバッグモードを設定してください。詳しくはデバッグモードの有効化を読んでください。