七天用 Go 寫個 docker(第五天)

pibigstar發表於2020-04-18

是不是以為太監了,哈哈,我又回來了
檢視完整原始碼

通過前面四天,我們其實已經基本實現了docker的最核心的功能,後面幾天,我將帶大家實現一些docker的其他命令,今天我們主要是來實現一下 docker logs 功能,也就是檢視docker內部日誌

寫日誌

說下總體思路,這個功能其實比較簡單,說白了,就是之前往控制檯輸出,現在改成往檔案裡面輸出就好了,我們通過docker logs 檢視日誌,也就是開啟該檔案,顯示該檔案裡面的內容

開始改造

我們將之前的tty傳遞到建立父級執行緒哪裡也就是process.go 的NewParentProcess函式 ,tty 也即是 -ti 引數,也就是以命令列互動模式啟動,如果使用者沒有輸入 -ti, 那麼我就將日誌資訊輸出到檔案裡,這裡我們將容器的Name作為檔名,後面方便我們通過容器名直接查詢該容器裡面的日誌。

func NewParentProcess(tty bool, volume, containerName, imageName string, envs []string) (*exec.Cmd, *os.File) {
 // .....
 if tty {
  cmd.Stdin = os.Stdin
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
 } else {
  // 把日誌輸出到檔案裡
  logDir := path.Join(common.DefaultContainerInfoPath, containerName)
  if _, err := os.Stat(logDir); err != nil && os.IsNotExist(err) {
   err := os.MkdirAll(logDir, os.ModePerm)
   if err != nil {
    logrus.Errorf("mkdir container log, err: %v", err)
   }
  }
  logFileName := path.Join(logDir, common.ContainerLogFileName)
  file, err := os.Create(logFileName)
  if err != nil {
   logrus.Errorf("create log file, err: %v", err)
  }
  // 將cmd的輸出流改到檔案流中
  cmd.Stdout = file
 }
}

檢視日誌

新增一個command命令引數: logs

`var logCommand = cli.Command{
 Name:  "logs",
 Usage: "look container log",
 Action: func(ctx *cli.Context) error {
  if len(ctx.Args()) < 1 {
   return fmt.Errorf("missing container name")
  }
  containerName := ctx.Args().Get(0)
  container.LookContainerLog(containerName)
  return nil
 },
}

看一下 LookContainerLog 的具體實現,主要就是讀檔案….

// 檢視容器內日誌資訊
func LookContainerLog(containerName string) {
 logFileName := path.Join(common.DefaultContainerInfoPath, containerName, common.ContainerLogFileName)
 file, err := os.Open(logFileName)
 if err != nil {
  logrus.Errorf("open log file, path: %s, err: %v", logFileName, err)
 }
 bs, err := ioutil.ReadAll(file)
 if err != nil {
  logrus.Errorf("read log file, err: %v", err)
 }
 _, _ = fmt.Fprint(os.Stdout, string(bs))
}

雖然木人關注,但是我還是厚著臉把公眾號放上來了,希望能和大家共同成長。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章