通过前面四天,我们其实已经基本实现了docker 的最核心的功能,后面几天,我将带大家实现一些 docker 的其他命令,今天我们主要是来实现一下 docker logs 功能,也就是查看docker 内部日志

写日志

说下总体思路,这个功能其实比较简单,说白了,就是之前往控制台输出,现在改成往文件里面输出就好了,我们通过 docker logs 查看日志,也就是打开该文件,显示该文件里面的内容

开始改造

我们将之前的 tty传递到创建父级线程哪里也就是 process.goNewParentProcess函数 ,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))
}

转自:微信号 跟派大星学编程