Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Go runtime/trace 包详解

概述

runtime/trace 包包含为 Go 执行跟踪器生成跟踪的工具。

重要说明

  • 捕获广泛的执行事件(goroutine 创建/阻塞/解除阻塞、系统调用、GC 事件等)
  • 为大多数事件捕获纳秒级时间戳和堆栈跟踪
  • 可通过 go tool trace 工具分析和可视化
  • 支持用户注释(日志、区域、任务)
  • net/http/pprof 包配合提供 HTTP 接口

跟踪的事件类型

  • Goroutine 创建/阻塞/解除阻塞
  • 系统调用进入/退出/阻塞
  • GC 相关事件
  • 堆大小变化
  • 处理器启动/停止
  • CPU 分析样本(如果启用)

包导入

import "runtime/trace"

基本使用

示例 1:基本跟踪

package main

import (
    "os"
    "runtime/trace"
)

func main() {
    // 启用跟踪
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    // ... 程序的其余部分 ...
}

运行命令

# 运行程序并生成跟踪文件
go run main.go > trace.out

# 使用 trace 工具分析
go tool trace trace.out

示例 2:完整的跟踪程序

package main

import (
    "fmt"
    "os"
    "runtime/trace"
    "time"
)

func main() {
    f, err := os.Create("trace.out")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    
    if err := trace.Start(f); err != nil {
        panic(err)
    }
    defer trace.Stop()
    
    // 执行一些工作
    work()
    
    fmt.Println("Trace written to trace.out")
    fmt.Println("Run: go tool trace trace.out")
}

func work() {
    // 模拟工作
    time.Sleep(100 * time.Millisecond)
}

函数详解(按 a-z 排序)

IsEnabled

func IsEnabled() bool

说明:报告是否启用了跟踪。此信息仅供参考,跟踪状态可能在此函数返回时已更改。

使用示例

package main

import (
    "fmt"
    "runtime/trace"
)

func main() {
    fmt.Printf("Tracing enabled: %v\n", trace.IsEnabled())
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    fmt.Printf("Tracing enabled: %v\n", trace.IsEnabled())
}

运行结果

Tracing enabled: false
Tracing enabled: true

Log

func Log(ctx context.Context, category, message string)

说明:发出带有给定类别和消息的时间戳事件。

使用示例

package main

import (
    "context"
    "runtime/trace"
    "time"
)

func processOrder(ctx context.Context, orderID string) {
    trace.Log(ctx, "order", "Processing order: "+orderID)
    
    // 处理订单
    time.Sleep(10 * time.Millisecond)
    
    trace.Log(ctx, "order", "Completed order: "+orderID)
}

func main() {
    ctx := context.Background()
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    processOrder(ctx, "ORD-123")
    processOrder(ctx, "ORD-456")
}

Logf

func Logf(ctx context.Context, category, format string, args ...interface{})

说明:类似于 Log,但使用指定的格式说明符格式化值。

使用示例

package main

import (
    "context"
    "runtime/trace"
)

func processItem(ctx context.Context, id, quantity int) {
    trace.Logf(ctx, "inventory", "Processing item %d, quantity: %d", id, quantity)
    
    // 处理物品
}

func main() {
    ctx := context.Background()
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    for i := 0; i < 10; i++ {
        processItem(ctx, i, i*10)
    }
}

Start

func Start(w io.Writer) error

说明:为当前程序启用跟踪。跟踪期间,跟踪数据将被缓冲并写入 w。

使用示例

package main

import (
    "log"
    "os"
    "runtime/trace"
)

func main() {
    f, err := os.Create("trace.out")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    if err := trace.Start(f); err != nil {
        log.Fatal(err)
    }
    defer trace.Stop()
    
    // ... 程序的其余部分 ...
}

Stop

func Stop()

说明:停止当前的跟踪(如果有的话)。仅在所有跟踪写入完成后才返回。

使用示例:参见 Start 函数示例。

WithRegion

func WithRegion(ctx context.Context, regionType string, fn func())

说明:启动与调用 goroutine 关联的区域,运行 fn,然后结束区域。

使用示例

package main

import (
    "context"
    "runtime/trace"
    "time"
)

func makeCappuccino(ctx context.Context) {
    trace.WithRegion(ctx, "makeCappuccino", func() {
        trace.Log(ctx, "step", "Starting cappuccino")
        
        trace.WithRegion(ctx, "steamMilk", func() {
            time.Sleep(10 * time.Millisecond)
        })
        
        trace.WithRegion(ctx, "extractCoffee", func() {
            time.Sleep(15 * time.Millisecond)
        })
        
        trace.WithRegion(ctx, "mixMilkCoffee", func() {
            time.Sleep(5 * time.Millisecond)
        })
        
        trace.Log(ctx, "step", "Cappuccino ready")
    })
}

func main() {
    ctx := context.Background()
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    makeCappuccino(ctx)
}

类型详解

FlightRecorder

type FlightRecorder struct{}

说明:表示 Go 执行跟踪的单个消费者。它跟踪运行时生成的执行跟踪的移动窗口,始终包含最近的跟踪数据。

NewFlightRecorder

func NewFlightRecorder(cfg FlightRecorderConfig) *FlightRecorder

说明:从提供的配置创建新的飞行记录器。

使用示例

package main

import (
    "os"
    "runtime/trace"
    "time"
)

func main() {
    // 创建飞行记录器
    fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{})
    
    if err := fr.Start(); err != nil {
        panic(err)
    }
    
    // 运行一段时间
    time.Sleep(1 * time.Second)
    
    // 写入跟踪数据
    f, _ := os.Create("flight.out")
    defer f.Close()
    
    fr.WriteTo(f)
    fr.Stop()
}

Enabled

func (fr *FlightRecorder) Enabled() bool

说明:如果飞行记录器处于活动状态则返回 true。

使用示例

package main

import (
    "fmt"
    "runtime/trace"
)

func main() {
    fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{})
    
    fmt.Printf("Before start: %v\n", fr.Enabled())
    
    fr.Start()
    fmt.Printf("After start: %v\n", fr.Enabled())
    
    fr.Stop()
    fmt.Printf("After stop: %v\n", fr.Enabled())
}

运行结果

Before start: false
After start: true
After stop: false

Start

func (fr *FlightRecorder) Start() error

说明:激活飞行记录器并开始记录跟踪数据。

使用示例:参见 NewFlightRecorder 示例。

Stop

func (fr *FlightRecorder) Stop()

说明:结束跟踪数据的记录。

使用示例:参见 NewFlightRecorder 示例。

WriteTo

func (fr *FlightRecorder) WriteTo(w io.Writer) (int64, error)

说明:快照飞行记录器跟踪的移动窗口。

使用示例

package main

import (
    "os"
    "runtime/trace"
    "time"
)

func main() {
    fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{})
    fr.Start()
    defer fr.Stop()
    
    // 模拟工作
    time.Sleep(100 * time.Millisecond)
    
    // 写入当前窗口的跟踪数据
    f, _ := os.Create("snapshot.out")
    defer f.Close()
    
    n, err := fr.WriteTo(f)
    if err != nil {
        panic(err)
    }
    
    println("Written bytes:", n)
}

FlightRecorderConfig

type FlightRecorderConfig struct{}

说明:飞行记录器配置。目前为空结构,用于未来扩展。

Region

type Region struct{}

说明:Region 是跟踪其执行时间间隔的代码区域。

StartRegion

func StartRegion(ctx context.Context, regionType string) *Region

说明:启动区域并返回它。必须在启动区域的同一 goroutine 中调用返回的 Region 的 End 方法。

使用示例

package main

import (
    "context"
    "runtime/trace"
    "time"
)

func process(ctx context.Context) {
    // 推荐用法
    defer trace.StartRegion(ctx, "process").End()
    
    // 处理逻辑
    time.Sleep(10 * time.Millisecond)
    
    // 嵌套区域
    defer trace.StartRegion(ctx, "subTask").End()
    time.Sleep(5 * time.Millisecond)
}

func main() {
    ctx := context.Background()
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    process(ctx)
}

End

func (r *Region) End()

说明:标记跟踪代码区域的结束。

使用示例:参见 StartRegion 示例。

Task

type Task struct{}

说明:Task 是用于跟踪用户定义的逻辑操作的数据类型。

NewTask

func NewTask(pctx context.Context, taskType string) (context.Context, *Task)

说明:创建类型为 taskType 的任务实例,并返回它以及携带任务的 Context。

使用示例

package main

import (
    "context"
    "runtime/trace"
    "time"
)

func handleRequest(ctx context.Context, requestID string) {
    ctx, task := trace.NewTask(ctx, "handleRequest")
    defer task.End()
    
    trace.Log(ctx, "requestID", requestID)
    
    // 主处理逻辑
    trace.WithRegion(ctx, "main", func() {
        time.Sleep(10 * time.Millisecond)
    })
    
    // 在单独的 goroutine 中继续处理
    go func() {
        defer task.End()
        trace.WithRegion(ctx, "async", func() {
            time.Sleep(5 * time.Millisecond)
        })
    }()
}

func main() {
    ctx := context.Background()
    
    trace.Start(os.Stdout)
    defer trace.Stop()
    
    handleRequest(ctx, "req-123")
    
    time.Sleep(100 * time.Millisecond)
}

End

func (t *Task) End()

说明:标记 Task 所表示的操作的结束。

使用示例:参见 NewTask 示例。

典型示例

示例 1:Web 服务器跟踪

package main

import (
    "fmt"
    "net/http"
    "os"
    "runtime/trace"
    "time"
)

func handler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    
    trace.Logf(ctx, "http", "Handling request: %s %s", r.Method, r.URL.Path)
    
    // 模拟处理
    time.Sleep(10 * time.Millisecond)
    
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path)
}

func main() {
    // 启用跟踪
    f, _ := os.Create("server.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    http.HandleFunc("/", handler)
    
    fmt.Println("Server starting on :8080")
    
    // 运行 10 秒
    go func() {
        time.Sleep(10 * time.Second)
        os.Exit(0)
    }()
    
    http.ListenAndServe(":8080", nil)
}

示例 2:数据库操作跟踪

package main

import (
    "context"
    "database/sql"
    "fmt"
    "runtime/trace"
    "time"

    _ "github.com/mattn/go-sqlite3"
)

func queryUsers(ctx context.Context, db *sql.DB) ([]string, error) {
    ctx, task := trace.NewTask(ctx, "queryUsers")
    defer task.End()
    
    trace.Log(ctx, "query", "SELECT * FROM users")
    
    rows, err := db.QueryContext(ctx, "SELECT name FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    
    var names []string
    for rows.Next() {
        var name string
        if err := rows.Scan(&name); err != nil {
            return nil, err
        }
        names = append(names, name)
    }
    
    trace.Logf(ctx, "result", "Found %d users", len(names))
    return names, nil
}

func main() {
    db, _ := sql.Open("sqlite3", ":memory:")
    defer db.Close()
    
    // 创建表
    db.Exec("CREATE TABLE users (name TEXT)")
    db.Exec("INSERT INTO users VALUES ('Alice'), ('Bob')")
    
    // 启用跟踪
    f, _ := os.Create("db.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    ctx := context.Background()
    names, err := queryUsers(ctx, db)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("Users:", names)
}

示例 3:并发任务跟踪

package main

import (
    "context"
    "fmt"
    "runtime/trace"
    "sync"
    "time"
)

func worker(ctx context.Context, id int, wg *sync.WaitGroup) {
    defer wg.Done()
    
    ctx, task := trace.NewTask(ctx, "worker")
    defer task.End()
    
    trace.Logf(ctx, "worker", "Worker %d starting", id)
    
    // 模拟工作
    time.Sleep(time.Duration(id+1) * 10 * time.Millisecond)
    
    trace.Logf(ctx, "worker", "Worker %d done", id)
}

func main() {
    ctx := context.Background()
    
    // 启用跟踪
    f, _ := os.Create("concurrent.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    var wg sync.WaitGroup
    
    // 启动多个 worker
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(ctx, i, &wg)
    }
    
    wg.Wait()
    
    fmt.Println("All workers completed")
}

示例 4:管道处理跟踪

package main

import (
    "context"
    "fmt"
    "runtime/trace"
    "time"
)

func stage1(ctx context.Context, in <-chan int, out chan<- int) {
    ctx, task := trace.NewTask(ctx, "stage1")
    defer task.End()
    
    for n := range in {
        trace.WithRegion(ctx, "process", func() {
            result := n * 2
            trace.Logf(ctx, "data", "%d -> %d", n, result)
            out <- result
        })
    }
    close(out)
}

func stage2(ctx context.Context, in <-chan int, out chan<- int) {
    ctx, task := trace.NewTask(ctx, "stage2")
    defer task.End()
    
    for n := range in {
        trace.WithRegion(ctx, "process", func() {
            result := n + 1
            trace.Logf(ctx, "data", "%d -> %d", n, result)
            out <- result
        })
    }
    close(out)
}

func main() {
    ctx := context.Background()
    
    // 启用跟踪
    f, _ := os.Create("pipeline.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    in := make(chan int)
    mid := make(chan int)
    out := make(chan int)
    
    go stage1(ctx, in, mid)
    go stage2(ctx, mid, out)
    
    // 发送数据
    go func() {
        for i := 0; i < 5; i++ {
            in <- i
            time.Sleep(10 * time.Millisecond)
        }
        close(in)
    }()
    
    // 接收结果
    for result := range out {
        fmt.Println("Result:", result)
    }
}

示例 5:批处理作业跟踪

package main

import (
    "context"
    "fmt"
    "runtime/trace"
    "sync"
    "time"
)

type BatchJob struct {
    ID    string
    Items []int
}

func processBatch(ctx context.Context, job BatchJob) {
    ctx, task := trace.NewTask(ctx, "processBatch")
    defer task.End()
    
    trace.Logf(ctx, "job", "Processing batch %s with %d items", job.ID, len(job.Items))
    
    var wg sync.WaitGroup
    results := make(chan int, len(job.Items))
    
    // 并发处理每个项目
    for _, item := range job.Items {
        wg.Add(1)
        go func(item int) {
            defer wg.Done()
            
            ctx, itemTask := trace.NewTask(ctx, "processItem")
            defer itemTask.End()
            
            // 模拟处理
            time.Sleep(5 * time.Millisecond)
            result := item * 2
            
            trace.Logf(ctx, "result", "Item %d -> %d", item, result)
            results <- result
        }(item)
    }
    
    // 等待所有项目完成
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // 收集结果
    var total int
    for result := range results {
        total += result
    }
    
    trace.Logf(ctx, "summary", "Batch %s total: %d", job.ID, total)
}

func main() {
    ctx := context.Background()
    
    // 启用跟踪
    f, _ := os.Create("batch.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    // 处理多个批次
    jobs := []BatchJob{
        {ID: "batch-1", Items: []int{1, 2, 3}},
        {ID: "batch-2", Items: []int{4, 5, 6}},
        {ID: "batch-3", Items: []int{7, 8, 9}},
    }
    
    for _, job := range jobs {
        processBatch(ctx, job)
    }
    
    fmt.Println("All batches processed")
}

示例 6:HTTP 客户端请求跟踪

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "runtime/trace"
    "time"
)

func httpClientDo(ctx context.Context, url string) (string, error) {
    ctx, task := trace.NewTask(ctx, "httpClientDo")
    defer task.End()
    
    trace.Logf(ctx, "http", "GET %s", url)
    
    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return "", err
    }
    
    client := &http.Client{Timeout: 5 * time.Second}
    
    trace.WithRegion(ctx, "request", func() {
        resp, err := client.Do(req)
        if err != nil {
            trace.Logf(ctx, "error", "Request failed: %v", err)
            return
        }
        defer resp.Body.Close()
        
        trace.Logf(ctx, "response", "Status: %s", resp.Status)
        
        body, _ := io.ReadAll(resp.Body)
        trace.Logf(ctx, "body", "Read %d bytes", len(body))
    })
    
    return "success", nil
}

func main() {
    ctx := context.Background()
    
    // 启用跟踪
    f, _ := os.Create("http.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    urls := []string{
        "https://httpbin.org/get",
        "https://httpbin.org/status/200",
    }
    
    for _, url := range urls {
        if _, err := httpClientDo(ctx, url); err != nil {
            fmt.Printf("Error: %v\n", err)
        }
    }
}

示例 7:定时任务跟踪

package main

import (
    "context"
    "fmt"
    "runtime/trace"
    "time"
)

func scheduledTask(ctx context.Context, name string, interval time.Duration, stop <-chan struct{}) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()
    
    for {
        select {
        case <-ticker.C:
            ctx, task := trace.NewTask(ctx, name)
            
            trace.WithRegion(ctx, "execution", func() {
                trace.Logf(ctx, "tick", "Running %s at %v", name, time.Now())
                // 执行任务
                time.Sleep(10 * time.Millisecond)
            })
            
            task.End()
            
        case <-stop:
            trace.Logf(ctx, "stop", "Stopping %s", name)
            return
        }
    }
}

func main() {
    ctx := context.Background()
    stop := make(chan struct{})
    
    // 启用跟踪
    f, _ := os.Create("scheduler.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    // 启动定时任务
    go scheduledTask(ctx, "cleanup", 100*time.Millisecond, stop)
    go scheduledTask(ctx, "metrics", 150*time.Millisecond, stop)
    
    // 运行 1 秒
    time.Sleep(1 * time.Second)
    close(stop)
    
    time.Sleep(100 * time.Millisecond)
    fmt.Println("Scheduler stopped")
}

示例 8:性能比较跟踪

package main

import (
    "fmt"
    "os"
    "runtime/trace"
    "sort"
    "time"
)

// 低效版本
func bubbleSort(arr []int) []int {
    n := len(arr)
    for i := 0; i < n-1; i++ {
        for j := 0; j < n-i-1; j++ {
            if arr[j] > arr[j+1] {
                arr[j], arr[j+1] = arr[j+1], arr[j]
            }
        }
    }
    return arr
}

// 高效版本
func quickSort(arr []int) []int {
    if len(arr) <= 1 {
        return arr
    }
    
    pivot := arr[len(arr)/2]
    var left, middle, right []int
    
    for _, v := range arr {
        switch {
        case v < pivot:
            left = append(left, v)
        case v == pivot:
            middle = append(middle, v)
        case v > pivot:
            right = append(right, v)
        }
    }
    
    return append(append(quickSort(left), middle...), quickSort(right)...)
}

func benchmark(ctx context.Context, name string, sortFn func([]int) []int) {
    ctx, task := trace.NewTask(ctx, "benchmark")
    defer task.End()
    
    trace.Log(ctx, "algorithm", name)
    
    // 生成随机数据
    data := make([]int, 1000)
    for i := range data {
        data[i] = (i * 17) % 1000
    }
    
    start := time.Now()
    sortFn(data)
    elapsed := time.Since(start)
    
    trace.Logf(ctx, "result", "%s took %v", name, elapsed)
    fmt.Printf("%s: %v\n", name, elapsed)
}

func main() {
    ctx := context.Background()
    
    // 启用跟踪
    f, _ := os.Create("sort.trace")
    defer f.Close()
    
    trace.Start(f)
    defer trace.Stop()
    
    // 比较两种排序算法
    benchmark(ctx, "bubbleSort", func(arr []int) []int {
        arrCopy := make([]int, len(arr))
        copy(arrCopy, arr)
        return bubbleSort(arrCopy)
    })
    
    benchmark(ctx, "quickSort", func(arr []int) []int {
        arrCopy := make([]int, len(arr))
        copy(arrCopy, arr)
        return quickSort(arrCopy)
    })
    
    // 与标准库比较
    benchmark(ctx, "stdlib", func(arr []int) []int {
        arrCopy := make([]int, len(arr))
        copy(arrCopy, arr)
        sort.Ints(arrCopy)
        return arrCopy
    })
}

用户注释 API

日志(Log)

用于记录执行过程中的事件。

// 基本日志
trace.Log(ctx, "category", "message")

// 格式化日志
trace.Logf(ctx, "category", "format: %d, %s", num, str)

区域(Region)

用于标记代码执行的时间区间。

// 使用 WithRegion(推荐)
trace.WithRegion(ctx, "regionType", func() {
    // 代码
})

// 使用 StartRegion/End
region := trace.StartRegion(ctx, "regionType")
defer region.End()

任务(Task)

用于跟踪逻辑操作,可跨多个 goroutine。

ctx, task := trace.NewTask(ctx, "taskType")
defer task.End()

// 在任务中记录日志
trace.Log(ctx, "key", "value")

// 在任务中创建区域
trace.WithRegion(ctx, "regionType", func() {
    // 代码
})

// 在另一个 goroutine 中使用任务
go func() {
    defer task.End()
    // 处理
}()

最佳实践

1. 始终使用 defer 停止跟踪

// ✅ 推荐
f, _ := os.Create("trace.out")
defer f.Close()
trace.Start(f)
defer trace.Stop()

// ❌ 不推荐
f, _ := os.Create("trace.out")
trace.Start(f)
// 可能忘记 Stop

2. 使用有意义的类别和类型

// ✅ 推荐
trace.Log(ctx, "database", "Query executed")
trace.WithRegion(ctx, "authentication", func() {})
ctx, task := trace.NewTask(ctx, "processOrder")

// ❌ 不推荐
trace.Log(ctx, "", "did something")
trace.WithRegion(ctx, "stuff", func() {})

3. 任务与上下文配合使用

// ✅ 推荐
func handleRequest(ctx context.Context) {
    ctx, task := trace.NewTask(ctx, "handleRequest")
    defer task.End()
    
    // 传递 ctx 给子函数
    process(ctx)
}

// ❌ 不推荐
func handleRequest(ctx context.Context) {
    ctx, task := trace.NewTask(ctx, "handleRequest")
    defer task.End()
    
    // 不传递 ctx
    process(context.Background())
}

4. 区域应该嵌套

// ✅ 推荐
trace.WithRegion(ctx, "outer", func() {
    trace.WithRegion(ctx, "inner", func() {
        // 代码
    })
})

// ❌ 不推荐:区域交叉
trace.WithRegion(ctx, "outer", func() {
    go func() {
        trace.WithRegion(ctx, "inner", func() {})
    }()
})

5. 生产环境谨慎使用

// ✅ 推荐:通过 flag 控制
var tracing = flag.Bool("trace", false, "enable tracing")

if *tracing {
    f, _ := os.Create("trace.out")
    defer f.Close()
    trace.Start(f)
    defer trace.Stop()
}

与其他包配合

net/http/pprof

package main

import (
    _ "net/http/pprof"
    "net/http"
)

func main() {
    // 提供 /debug/pprof/trace 端点
    http.ListenAndServe("localhost:6060", nil)
}

testing

package mypkg

import "testing"

func TestSomething(b *testing.B) {
    // 使用 go test -trace=trace.out
    for i := 0; i < b.N; i++ {
        // 测试代码
    }
}

context

package main

import (
    "context"
    "runtime/trace"
)

func main() {
    ctx := context.Background()
    
    // 添加超时
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()
    
    // 使用任务
    ctx, task := trace.NewTask(ctx, "timedTask")
    defer task.End()
    
    // 执行
    doWork(ctx)
}

快速参考

函数

函数参数返回值说明
IsEnabled-bool检查是否启用跟踪
Logctx, category, message-记录日志
Logfctx, category, format, args-格式化日志
Startw io.Writererror开始跟踪
Stop--停止跟踪
WithRegionctx, regionType, fn-执行区域代码

类型

类型说明
FlightRecorder飞行记录器
FlightRecorderConfig飞行记录器配置
Region代码区域
Task逻辑任务

FlightRecorder 方法

方法返回值说明
NewFlightRecorder*FlightRecorder创建记录器
Enabledbool检查是否活动
Starterror开始记录
Stop-停止记录
WriteToint64, error写入快照

Region 方法

方法返回值说明
StartRegion*Region开始区域
End-结束区域

Task 方法

方法返回值说明
NewTaskContext, *Task创建任务
End-结束任务

注意事项

1. 性能开销

  • 跟踪会影响程序性能
  • 避免在生产环境长时间启用
  • 使用采样或条件启用

2. 文件大小

  • 跟踪文件可能很大
  • 及时停止跟踪
  • 考虑使用 FlightRecorder 获取窗口快照

3. 上下文传递

  • 确保正确传递 context
  • 任务依赖上下文传播
  • 避免丢失上下文

4. 区域嵌套

  • 区域必须在同一 goroutine 中开始和结束
  • 区域应该正确嵌套
  • 使用 defer 确保结束

5. 工具兼容性

  • 使用 go tool trace 分析
  • 确保 Go 版本兼容
  • 跟踪格式可能随版本变化

总结

runtime/trace 包提供了 Go 程序执行跟踪的完整工具集。

核心要点

  1. 使用 Start/Stop 启用和停止跟踪
  2. 使用 Log/WithRegion/NewTask 添加用户注释
  3. 任务可以跨 goroutine 跟踪逻辑操作
  4. 区域用于标记代码执行区间
  5. 使用 go tool trace 分析和可视化

主要用途

  • 性能分析和瓶颈识别
  • Goroutine 调度分析
  • GC 行为观察
  • 并发问题调试
  • 延迟分布分析

工具链

# 生成跟踪
go test -trace=trace.out
go run main.go > trace.out

# 分析跟踪
go tool trace trace.out

# Web 界面
go tool pprof -http=:8080 trace.out

与 pprof 的区别

  • pprof - 性能分析(CPU、内存等)
  • trace - 执行跟踪(事件、时间线)
  • 两者配合使用效果更佳