我已经搜索过它,但只找到了here和here,但它并没有解决我的问题。
我如何使用标准方法识别分隔JAVA和线程ID的并发日志的日志?因为如果我有一个并发方法,那么日志将在输出中混合打印,所以我认为LOGGER需要有一种方法来识别每个请求"线程"
例如:
package main
import "log"
func main() {
/* simulating 10000 users requests */
i := 1;
for ;i < 10000; i++ {
go getHello(i)
}
}
func getHello(d int){
log.Printf("m=getHello, i=%d,begin", d)
log.Println("m=getHello, processing the hello message")
log.Printf("m=getHello, i=%d, end", d)
}
输出
2016/07/29 15:59:46 m=getHello, i=1017,begin
2016/07/29 15:59:46 m=getHello, processing the hello message
2016/07/29 15:59:46 m=getHello, i=1017, end
2016/07/29 15:59:46 m=getHello, processing the hello message
2016/07/29 15:59:46 m=getHello, i=1038, end
2016/07/29 15:59:46 m=getHello, i=311,begin
2016/07/29 15:59:46 m=getHello, processing the hello message
2016/07/29 15:59:46 m=getHello, i=311, end
2016/07/29 15:59:46 m=getHello, i=1023,begin
2016/07/29 15:59:46 m=getHello, processing the hello message
2016/07/29 15:59:46 m=getHello, i=1023, end
2016/07/29 15:59:46 m=getHello, i=991,begin
2016/07/29 15:59:46 m=getHello, processing the hello message
2016/07/29 15:59:46 m=getHello, i=991, end
正如您所看到的,如果我没有int标志,则无法知道请求记录的内容。在java,c,c#,delphy例如我简单记录了线程id,一切正常。
你能帮我在Golang做些类似的事吗?感谢。
Obs:如果我的问题不好,请在评论中告诉我原因
答案 0 :(得分:7)
运行时没有可用的goroutine ID。 Goroutines比其他语言中的线程使用得更加自由,因此在更大的程序中,goroutine处理特定请求或项目的想法可能不太明确。
所以你需要自己通过一个ID进行日志记录。您可以自己通过int
,但context
模块对此非常方便:除了允许用户定义的值之外,它还可以处理项目取消和截止日期,这些也可能对您有用
这是一个如何使用它的粗略例子。我添加了一个简单的日志记录对象,可以用作上下文感知记录器。它记录创建上下文的ID。可能这个记录器会在一个真实的程序中包含它自己的包,并支持更多的日志包功能,而不仅仅是Printf
和Println
。
package main
import (
"fmt"
"log"
"sync"
"context"
)
type logger int
const loggerID = "logger_id"
func (l logger) Printf(s string, args ...interface{}) {
log.Printf("[id=%d] %s", l, fmt.Sprintf(s, args...))
}
func (l logger) Println(s string) {
log.Printf("[id=%d] %s\n", l, s)
}
func ctxWithLoggerID(ctx context.Context, id int) context.Context {
return context.WithValue(ctx, loggerID, id)
}
func getLogger(ctx context.Context) logger {
return logger(ctx.Value(loggerID).(int))
}
func main() {
ctx := context.Background()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go hello(ctxWithLoggerID(ctx, i), &wg)
}
wg.Wait()
}
func hello(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
log := getLogger(ctx)
log.Printf("hello begin")
log.Println("hello, processing the hello message")
log.Printf("hello, end")
}
这是您的问题的附带条件,但我在您的程序中添加了sync.WaitGroup
,以便main
等到所有工作人员完成后再退出。这允许使用较少数量的工作程序(10而不是原始10000)来测试代码。
答案 1 :(得分:0)
goroutines
与线程甚至进程非常不同。它们由go运行时管理,而不是您的操作系统。如果你做了一些非常繁重的工作,甚至可能在进程之间跳过相同的goroutine,因此很难给它们提供唯一的ID。
对于您使用给定int
的示例完全没问题,因为每个goroutine只处理一个数字。
答案 2 :(得分:0)
如果您不想在每个goroutine中传递一些int
,那么您可以尝试使用goroutine iself中的math/rand
包生成随机数。如果数字足够高(取决于您的负载),那么您将获得某种goroutine ID。
您可以找到生成here的随机数的示例。
您也可以用十六进制打印,因此很容易将该id与您在程序中可能拥有的其他int值区分开来。
这应该可以解决问题:
log.Printf("m=getHello, i=%#x,begin", d)
修改强> 此外,如果你想确定你的id在每个goroutine中是唯一的,那么你可以添加一些全局计数器并在每个goroutine中增加它。
import sync
var txCounter int
var counterMutex = &sync.Mutex{}
for {
go func() {
id := txCounter
counterMutex.Lock()
txCounter++
counterMutex.Unlock()
log.Printf("m=getHello, i=%#x,begin", id)
}()
}