运维八一 运维八一
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)

运维八一

运维,运维!
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)
  • Go

    • 前言

    • Go基础知识

    • Go基本语法

    • 实战项目:简单web服务

    • 基本数据类型

    • 内置运算符

    • 分支和循环

    • 函数 function

    • 结构体 struct

    • 方法 method

    • 实战项目:跟踪函数调用链

      • v0_1 使用 defer 跟踪函数的执行过程
      • v0_2 自动获取所跟踪函数的函数名
      • v0_3 增加 Goroutine 标识
      • v0_4 让输出的跟踪信息更具层次感
        • v0.4 让输出的跟踪信息更具层次感
      • v0_5 利用代码生成自动注入 Trace 函数
      • 总结
    • 接口 interface

    • 并发 concurrency

    • 指针

    • 实战项目:实现轻量级线程池

    • 实战项目:实现TCP服务器

    • go常用包

    • Gin框架

    • go随记

  • Python

  • Shell

  • Java

  • Vue

  • 前端

  • 编程浅尝
  • Go
  • 实战项目:跟踪函数调用链
lyndon
2022-06-07
目录

v0_4 让输出的跟踪信息更具层次感

# v0.4 让输出的跟踪信息更具层次感

对于程序员来说,缩进是最能体现出“层次感”的方法,如果将上面示例中 Goroutine 00001 的函数调用跟踪信息用如下的形式展示出来,函数的调用顺序更加一目了然:

g[00001]:    ->main.A1
g[00001]:        ->main.B1
g[00001]:            ->main.C1
g[00001]:                ->main.D
g[00001]:                <-main.D
g[00001]:            <-main.C1
g[00001]:        <-main.B1
g[00001]:    <-main.A1
1
2
3
4
5
6
7
8

代码如下:

// trace3/trace.go

func printTrace(id uint64, name, arrow string, indent int) {
    indents := ""
    for i := 0; i < indent; i++ {
        indents += "    "
    }
    fmt.Printf("g[%05d]:%s%s%s\n", id, indents, arrow, name)
}

var mu sync.Mutex
var m = make(map[uint64]int)

func Trace() func() {
    pc, _, _, ok := runtime.Caller(1)
    if !ok {
        panic("not found caller")
    }

    fn := runtime.FuncForPC(pc)
    name := fn.Name()
    gid := curGoroutineID()
    
    mu.Lock()
    indents := m[gid]    // 获取当前gid对应的缩进层次
    m[gid] = indents + 1 // 缩进层次+1后存入map
    mu.Unlock()
    printTrace(gid, name, "->", indents+1)
    return func() {
        mu.Lock()
        indents := m[gid]    // 获取当前gid对应的缩进层次
        m[gid] = indents - 1 // 缩进层次-1后存入map
        mu.Unlock()
        printTrace(gid, name, "<-", indents)
    }

}

/*
g[00001]:    ->main.A1
g[00001]:        ->main.B1
g[00001]:            ->main.C1
g[00001]:                ->main.D
g[00001]:                <-main.D
g[00001]:            <-main.C1
g[00001]:        <-main.B1
g[00001]:    <-main.A1
g[00018]:    ->main.A2
g[00018]:        ->main.B2
g[00018]:            ->main.C2
g[00018]:                ->main.D
g[00018]:                <-main.D
g[00018]:            <-main.C2
g[00018]:        <-main.B2
g[00018]:    <-main.A2
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

使用了一个 map 类型变量 m 来保存每个 Goroutine 当前的缩进信息:m 的 key 为 Goroutine 的 ID,值为缩进的层次。然后,考虑到 Trace 函数可能在并发环境中运行,根据“map 不支持并发写”的注意事项,增加了一个 sync.Mutex 实例 mu 用于同步对 m 的写操作。

这样,对于一个 Goroutine 来说,每次刚进入一个函数调用,我们就在输出入口跟踪信息之前,将缩进层次加一,并输出入口跟踪信息,加一后的缩进层次值也保存到 map 中。然后,在函数退出前,我们取出当前缩进层次值并输出出口跟踪信息,之后再将缩进层次减一后保存到 map 中。

除了增加缩进层次信息外,在这一版的 Trace 函数实现中,也把输出出入口跟踪信息的操作提取到了一个独立的函数 printTrace 中,这个函数会根据传入的 Goroutine ID、函数名、箭头类型与缩进层次值,按预定的格式拼接跟踪信息并输出。

上次更新: 2022/10/06, 00:04:41
v0_3 增加 Goroutine 标识
v0_5 利用代码生成自动注入 Trace 函数

← v0_3 增加 Goroutine 标识 v0_5 利用代码生成自动注入 Trace 函数→

最近更新
01
ctr和crictl显示镜像不一致
03-13
02
alpine镜像集成常用数据库客户端
03-13
03
create-cluster
02-26
更多文章>
Theme by Vdoing | Copyright © 2015-2024 op81.com
苏ICP备18041258号-2
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式