Golang相关的内容到底什么样才真正吸引人?

Golang相关的内容到底什么样才真正吸引人? 我一直在思考 @NobbZ 关于论坛衰落的那篇帖子。这很可惜,因为这里有很多非常聪明的人,我很享受与他们交流。

什么样的内容真的能引起人们的兴趣呢?我个人觉得,当有人遇到一个现实世界的问题,而我们能帮助他们解决,并引导一位Go语言新手走上正确的道路(比如让他们建立起基准测试/测试的思维模式)时,这很有趣。还有什么其他内容可能让你们觉得有趣吗?

另外——我想借此机会分享一件(对我来说)有点意思的事情。我不知怎么完全错过了这个公告:

go.dev

使用 slog 进行结构化日志记录 - Go 编程语言

缩略图

Go 1.21 标准库包含了一个新的结构化日志记录包,log/slog。

你们中有多少人在使用 log/slog


更多关于Golang相关的内容到底什么样才真正吸引人?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

记录任何对你有用的信息。slog 的意义在于它能让日志条目更容易用代码解析。

更多关于Golang相关的内容到底什么样才真正吸引人?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的——关于错误处理的提议修改是那些在GitHub上非常热门的问题之一,以至于每次我打开它,我的网页浏览器都快被“融化”了。我同意在论坛上讨论这些很有趣,但如果你希望自己的意见在提案中起作用,或许最好还是在GitHub等地方发表评论。

现实世界中的问题是一个坚实的基础,但我认为许多人会使用LLM或Stack Overflow来寻找答案。

一个不错的切入点可能是讨论语言或标准库的拟议变更。在Go代码仓库中,有一些非常活跃讨论的开放议题和提案,但我发现它们不太容易参与互动(除了给好点子点赞之外)——论坛可以是一个与更广泛受众讨论此类话题的好地方。

结构化日志记录更加一致(顾名思义)

这是否可以通过测量路由器中的每条路径来创建一种“性能偏差日志”?

func router() {
	start := time.Now()
	// executing the query etc...
	duration := time.Since(start)

	if duration > 200*time.Millisecond {
		slog.Warn("slow operation",
			"duration", duration,
			"path", r.URL.Path,
			"method", r.Method,
		)
	}
}

Dean_Davidson:

大家还有什么其他感兴趣的话题吗?

我只能代表我自己发言。在使用Go进行Web开发时,我发现关于这个主题的讨论很少。而且Web开发不仅仅专注于Go,但其基础是Go。

目前我还没有使用slog。只是一个简单的文本文件。请告诉我更多…

func init_log() {
	// Open or create the log file
	log.Println("Log start...")
	var err error
	log_file, err = os.OpenFile("log.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	log.SetOutput(log_file)
}

是的——但如果你让日志变得机器可读且可查询,你可能会记录该上下文下的所有操作,然后当你稍后查询日志信息时,再决定什么是“慢”的(例如,了解到你99%的请求都在30毫秒或更短时间内完成也可能很有用)。

但确实如此。整个想法是创建结构化日志,这样就不只是你(一个人)去解析成千上万行日志来寻找有用信息了。我曾经用Vim搜索一个10GB的非结构化日志文件(这个API是我从前任开发者那里继承的,他们不懂日志文件轮换的重要性!),这……至少可以说是相当困难。

那么——结构化日志记录对于可观测性以及以机器可读的方式查询日志的能力来说,是很有趣的。目前——大多数日志文件对于故障排查确实非常重要,但它们是以一种非常临时的方式编写的(例如 log.Println("Something unexpected happened"))。关于“为什么”需要结构化日志,可以阅读这里这里了解更多。

结构化日志记录更加一致(顾名思义),并且实际上将开发者需要编写的一些内容抽象掉了。引自文档

一条日志记录包含时间、级别、消息以及一组键值对,其中键是字符串,值可以是任何类型。

那么——考虑下面这条带有一个键值对的消息及其输出:

slog.Info("Hello structured logging", "Current User", "Dean")
// Output:
// 2025/09/04 13:43:29 INFO Hello structured logging "Current User"=Dean

我们选择记录什么,但我们只是传递键值对,我们并不真正关心或知道它的输出是什么。因此,例如,如果我们希望以后以 JSON 格式查询日志,我们可以将所有日志条目更改为 JSON:

var programLevel = new(slog.LevelVar) // Info by default
h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})
slog.SetDefault(slog.New(h))
slog.Info("Hello structured logging", "Current User", "Dean")
// Output:
// {"time":"2025-09-04T13:46:57.539335-07:00","level":"INFO","msg":"Hello structured logging","Current User":"Dean"}

并且你可以编写自己的处理器来输出任何你想要的内容。所以——主要思想是让所有日志都统一,从而可以被机器读取。并且让开发者不必过多地考虑它。

关于什么样的Go内容真正吸引人,我认为核心在于解决实际问题展示最佳实践。你提到的帮助新手建立基准测试思维就很好。让我分享几个具体例子:

1. 生产环境问题剖析

比如有人遇到goroutine泄漏,可以这样分析:

// 错误的示例:未控制goroutine数量
func processTasks(tasks []Task) {
    for _, task := range tasks {
        go func(t Task) {
            // 处理任务
        }(task)
    }
}

// 正确的模式:使用worker pool
func processTasksWithPool(tasks []Task, workers int) {
    ch := make(chan Task, len(tasks))
    var wg sync.WaitGroup
    
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for task := range ch {
                process(task)
            }
        }()
    }
    
    for _, task := range tasks {
        ch <- task
    }
    close(ch)
    wg.Wait()
}

2. 性能优化案例

展示如何从O(n²)优化到O(n):

// 优化前
func findPairsSlow(arr []int, target int) [][2]int {
    var pairs [][2]int
    for i := 0; i < len(arr); i++ {
        for j := i + 1; j < len(arr); j++ {
            if arr[i]+arr[j] == target {
                pairs = append(pairs, [2]int{arr[i], arr[j]})
            }
        }
    }
    return pairs
}

// 优化后:使用map
func findPairsFast(arr []int, target int) [][2]int {
    seen := make(map[int]bool)
    var pairs [][2]int
    
    for _, num := range arr {
        complement := target - num
        if seen[complement] {
            pairs = append(pairs, [2]int{complement, num})
        }
        seen[num] = true
    }
    return pairs
}

3. 关于slog的使用

我在生产环境中使用slog,这是我们的配置:

import "log/slog"

func setupLogger() *slog.Logger {
    handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug,
        ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
            if a.Key == slog.TimeKey {
                return slog.String("timestamp", time.Now().Format(time.RFC3339))
            }
            return a
        },
    })
    
    logger := slog.New(handler)
    slog.SetDefault(logger)
    return logger
}

// 使用示例
func processOrder(orderID string) {
    logger := slog.With(
        "order_id", orderID,
        "service", "payment",
    )
    
    logger.Info("processing order",
        "amount", 99.99,
        "currency", "USD",
    )
    
    // 输出结构化日志:
    // {"timestamp":"2024-01-15T10:30:00Z","level":"INFO","msg":"processing order",
    //  "order_id":"123","service":"payment","amount":99.99,"currency":"USD"}
}

4. 并发模式的实际应用

展示context在微服务中的正确用法:

func fetchUserData(ctx context.Context, userID string) (*User, error) {
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()
    
    // 并行获取用户信息
    var user User
    errCh := make(chan error, 2)
    
    go func() {
        profile, err := fetchProfile(ctx, userID)
        if err != nil {
            errCh <- fmt.Errorf("profile: %w", err)
            return
        }
        user.Profile = profile
        errCh <- nil
    }()
    
    go func() {
        orders, err := fetchOrders(ctx, userID)
        if err != nil {
            errCh <- fmt.Errorf("orders: %w", err)
            return
        }
        user.Orders = orders
        errCh <- nil
    }()
    
    // 等待所有goroutine完成或超时
    for i := 0; i < 2; i++ {
        select {
        case err := <-errCh:
            if err != nil {
                return nil, err
            }
        case <-ctx.Done():
            return nil, ctx.Err()
        }
    }
    
    return &user, nil
}

真正吸引人的内容通常包含:

  • 实际遇到的生产问题
  • 性能对比数据(benchmark结果)
  • 不同解决方案的trade-off分析
  • 标准库新特性(如slog)的实战应用
  • 并发模式的实际案例

slog确实是个很好的补充,特别是它的结构化日志和性能优化。我们在微服务中用它替换了zap,减少了依赖。关键是要展示为什么选择某个方案,而不仅仅是如何实现。

回到顶部