写点什么

自己动手写 Docker 系列 -- 5.3 实现 logs 命令查看容器日志

作者:
  • 2022 年 4 月 09 日
  • 本文字数:2768 字

    阅读完需:约 9 分钟

简介

在上篇中我们实现了查看正在运行中的容器列表,本章节我们来实现 logs 命令,来查看正在运行中的容器的运行日志

源码说明

同时放到了 Gitee 和 Github 上,都可进行获取



本章节对应的版本标签是:5.3,防止后面代码过多,不好查看,可切换到标签版本进行查看

代码实现

实现该功能的主要思路如下:


1 日志的保存:在使用-d 后台运行的时候,我们将文件的输出重定向到文件中,这样就将日志保存到了文件中,提供给后面查看


2 日志的查看:在日志运行过程中,文件已保存到约定的目录,我们只需要读取日志文件内容进行显示即可

运行日志的保存

我们约定将日志文件保存到指定位置


如下,在容器配置中,新增日志文件名称,这样日志文件对应的路径就是:/var/run/mydocker/{容器名}/container.log


var (  RUNNING             = "running"  STOP                = "stop"  EXIT                = "exited"  DefaultInfoLocation = "/var/run/mydocker/%s/"  ConfigName          = "config.json"  ContainerLogFile    = "container.log")
复制代码


然后将后台运行的容器的输出定向输入到文件中


在启动的时候,将容器名称传递进去,如果没有的话,随机生成(在以前章节中已实现)


func Run(tty, detach bool, cmdArray []string, config *subsystem.ResourceConfig, volume, containerName string) {  pwd, err := os.Getwd()  if err != nil {    log.Errorf("Run get pwd err: %v", err)    return  }  mntUrl := pwd + "/mnt/"  rootUrl := pwd + "/"  // 传入容器名  parent, writePipe := container.NewParentProcess(tty, containerName, rootUrl, mntUrl, volume)  if err := parent.Start(); err != nil {    log.Error(err)    // 如果fork进程出现异常,但有相关的文件已经进行了挂载,需要进行清理,避免后面运行报错时,需要手工清理    deleteWorkSpace(rootUrl, mntUrl, volume)    return  }  ......}
复制代码


然后在 fork 进程的时候,生成相关的文件,将标准输出重定向到文件中,如下


func NewParentProcess(tty bool, containerName, rootUrl, mntUrl, volume string) (*exec.Cmd, *os.File) {  ......  if tty {    cmd.Stdin = os.Stdin    cmd.Stdout = os.Stdout    cmd.Stderr = os.Stderr  } else {    // 创建日志保存文件夹    dirUrl := fmt.Sprintf(DefaultInfoLocation, containerName)    if err := os.MkdirAll(dirUrl, 0622); err != nil {      log.Errorf("mkdir dir %s, err: %v", dirUrl, err)      return nil, nil    }
// 生成日志文件 stdLogFilePath := dirUrl + ContainerLogFile stdLogFile, err := os.Create(stdLogFilePath) if err != nil { log.Errorf("create file %s, err: %v", stdLogFilePath, err) return nil, nil }
// 将输出定向输出到文件 cmd.Stdout = stdLogFile } ......}
复制代码


这样,我们就将容器的日志进行了保存

查看容器日志

查看日志就比较简单了,根据容器配置信息,找到日志存放文件,读取进行查看即可


新增 logs 命令:


func main() {  ......  app.Commands = []cli.Command{    command.InitCommand,    command.RunCommand,    command.CommitCommand,    command.ListCommand,    command.LogCommand,  }  .....}
复制代码


新增 logs 命令解析


var LogCommand = cli.Command{  Name:  "logs",  Usage: "print logs of a container",  Action: func(context *cli.Context) error {    if len(context.Args()) < 1 {      return fmt.Errorf("Missing container name")    }    containerName := context.Args().Get(0)    return run.LogContainer(containerName)  },}
复制代码


logs 查看的具体实现,读取容器日志文件,进行查看


func LogContainer(containerName string) error {  dirUrl := fmt.Sprintf(container.DefaultInfoLocation, containerName)  logFilePath := dirUrl + container.ContainerLogFile  file, err := os.Open(logFilePath)  defer file.Close()  if err != nil {    return fmt.Errorf("open file %s, err: %v", logFilePath, err)  }
content, err := ioutil.ReadAll(file) if err != nil { return fmt.Errorf("read file %s, err: %v", logFilePath, err) } fmt.Fprint(os.Stdout, string(content)) return nil}
复制代码

运行测试

我们运行一个后台的 top 命令容器,然后确认查看相关的信息是否正确:


 root@lw-Code-01-Series-PF5NU1G  ~/code/go/dockerDemo   main  ./main run -d -name bird top                                                                                          ✔  ⚡  374  04:58:58{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-08T04:59:03+08:00"}{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-08T04:59:03+08:00"}{"level":"info","msg":"all command is : top","time":"2022-04-08T04:59:03+08:00"}{"level":"info","msg":"parent process run","time":"2022-04-08T04:59:03+08:00"}
root@lw-Code-01-Series-PF5NU1G  ~/code/go/dockerDemo   main  ./main ps  SIG(127) ↵  ⚡  375  04:59:03ID NAME PID STATUS COMMAND CREATED3391689383 bird 28013 running top 8000-04-04 00:00:00
root@lw-Code-01-Series-PF5NU1G  ~/code/go/dockerDemo   main  tree /var/run/mydocker  ✔  ⚡  376  04:59:07/var/run/mydocker└── bird ├── config.json └── container.log
1 directory, 2 files
root@lw-Code-01-Series-PF5NU1G  ~/code/go/dockerDemo   main  ./main logs bird  SIG(127) ↵  ⚡  375  04:59:03Mem: 10193564K used, 22080872K free, 55104K shrd, 106496K buff, 3969012K cachedCPU: 0.0% usr 1.3% sys 0.9% nic 97.5% idle 0.0% io 0.0% irq 0.0% sirqLoad average: 0.19 0.34 0.47 2/1222 6 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
复制代码


发布于: 刚刚阅读数: 2
用户头像

关注

还未添加个人签名 2018.09.09 加入

代码是门手艺活,也是门艺术活

评论

发布
暂无评论
自己动手写Docker系列 -- 5.3实现logs命令查看容器日志_golang_萧_InfoQ写作平台