我正在編寫一個程序,該程序從 CLI 命令讀取 stderr 并通過 gRPC 流將 stderr 日志流式傳輸到客戶端。cmd 實例化如下(CLI 命令需要配置,我將其作為 stdin 傳遞):ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Duration(t)*time.Second)defer cancel()cmd := exec.CommandContext(ctxTimeout, "java", "-jar", "/opt/myapp/myapp.jar", "scan", "-config", "-",)cmd.Stdin = config我使用兩個單獨的緩沖區:一個將 stderr“實時”流式傳輸到客戶端,另一個將日志保存在數據庫中。為此,我使用 io.MultiWriter 并將其映射到 cmd 標準輸入:bufStream := bytes.NewBuffer(make([]byte, 0, 4096))bufPersist := new(bytes.Buffer)stderr := io.MultiWriter(bufStream, bufPersist)// Map the command Standard Error Output to the multiwritercmd.Stderr = stderr最后,在啟動命令之前,我有一個 goroutine,它使用 bufio.Scanner 來讀取 stderr 緩沖區并通過 gRPC 逐行流式傳輸:// Go Routine to stream the scan job logsgo func() { for { select { case <-done: return default: scanner := bufio.NewScanner(bufStream) for scanner.Scan() { time.Sleep(3 * time.Second) logging.MyAppLog("warning", "%v", scanner.Text()) _ = stream.Send(&agentpb.ScanResultsResponse{ ScanLogsWebsocket: &agentpb.ScanLogFileResponseWB{ScanLogs: scanner.Bytes()}, }, ) } } }}()err := cmd.Run()done <- true我的問題是我必須time.sleep(time.Seconds * 3)在 goroutine 中使用才能獲得正確的輸出。如果沒有,我得到的輸出順序不正確并被截斷。我相信這是由于 io.multiwriter 和 bufio.scanner 不“同步”,但我想要一些有關最佳方法的指導。提前致謝。
1 回答

慕雪6442864
TA貢獻1812條經驗 獲得超5個贊
來自掃描儀文檔:
Bytes 返回調用 Scan 生成的最新令牌。底層數組可能指向將被后續調用 Scan 覆蓋的數據。它不進行分配。
gRPC 有自己的緩沖。這意味著當 Send 返回時,字節不一定已寫入線路,并且下一個 Scan 調用會修改尚未寫入的字節。
復制 Scan 返回的字節,應該沒問題:
for scanner.Scan() {
? ? b := append([]byte(nil), scanner.Bytes()...)
? ? stream.Send(&agentpb.ScanResultsResponse{
? ? ? ? ScanLogsWebsocket: &agentpb.ScanLogFileResponseWB{
? ? ? ? ? ? ScanLogs: b,
? ? ? ? },
? ? })
}
- 1 回答
- 0 關注
- 134 瀏覽
添加回答
舉報
0/150
提交
取消