0. 概述

在编写 Go 语言代码的时候,context 是一个非常常见的元素。但是,有时在搭配其他库时,我知道 context 里面包含某些信息,但是却不知道这些信息在 context 中的具体 key 是什么,所以这个时候除了调试之外,将 context 之中的数据打印出来不妨是一个好的选择。

但是,找了一圈,似乎没有看到一些比较简单的方式,最后用了反射的方法将所有的 context key 和 value 提取出来。

1. 代码

[[email protected]]# cat query_context.go
func TestContextPrint(t *testing.T) {
    var ctx = context.Background()
    ctx = context.WithValue(ctx, "hello", "world")
    ctx = context.WithValue(ctx, "世界", "你好")
    printContextInternals(ctx, false)
    t.Fail()
}

func printContextInternals(ctx context.Context, inner bool) {
    contextValues := reflect.ValueOf(ctx).Elem()
    contextKeys := reflect.TypeOf(ctx).Elem()

    if !inner {
        fmt.Printf("\nFields for %s.%s\n", contextKeys.PkgPath(), contextKeys.Name())
    }

    var keys []string
    if contextKeys.Kind() == reflect.Struct {
        for i := 0; i < contextValues.NumField(); i++ {
            reflectValue := contextValues.Field(i)
            reflectValue = reflect.NewAt(reflectValue.Type(), unsafe.Pointer(reflectValue.UnsafeAddr())).Elem()

            reflectField := contextKeys.Field(i)

            if reflectField.Name == "Context" {
                printContextInternals(reflectValue.Interface().(context.Context), true)
            } else {
                if reflectField.Name == "key" {
                    keys = append(keys, reflectValue.Interface().(string))
                }
            }
        }
    }

    for _, key := range keys {
        fmt.Printf("ctx.%s = %+v\n", key, ctx.Value(key))
    }
}

2. Ref