go基于docker SDK,前端页面动态显示容器日志

go基于docker SDK,前端页面动态显示容器日志

需要用到的包

github.com/gin-gonic/gin
nhooyr.io/websocket
github.com/docker/docker/client

文件目录

├── docker
│   ├── conn.go
│   └── conn_test.go
├── go.mod
├── go.sum
├── html
│   └── index.html
└── main.go

静态页面

代码展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>

    </style>
</head>
<body>
<div id="app">
    <div>
        <input type="button" value="查看" v-on:click="connWs">
    </div>
    <div v-for="msgn in msgList">
        <span>${ msgn }</span>
    </div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
    let gWs
    let app = new Vue({
        el: '#app',
        data: {
            msgList: [],
            msg: "",
        },
        methods: {
            connWs: function () {
                let that = this
                let host = location.host;
                gWs = new WebSocket("ws://" + host + "/ws");
                gWs.onopen = function () {

                }
                gWs.onmessage = function (evt) {
                    let receive = JSON.parse(evt.data)
                    that.msgList.push(receive)
                }
                gWs.onerror = function (evt) {
                    console.log("websocket 发生错误")
                    console.log(evt)
                }
                gWs.onclose = function () {
                    console.log("conn 已经关闭")
                }
            },
            sendMessage: function () {
                let msg = JSON.stringify({"content": this.msg})
                gWs.send(msg)
                this.msg = ""
            }
        },
        delimiters: ['${', '}']
    })
</script>
</html>

前端 WebSocket 的核心是构造函数和几个回调函数。

  • new WebSocket:创建一个 WebSocket 实例,提供服务端的 ws 地址,地址可以跟 HTTP 协议一样,加上请求参数。注意,如果你使用 HTTPS 协议,相应的 WebSocket 地址协议要改为 wss;
  • WebSocket.onopen:用于指定连接成功后的回调函数;
  • WebSocket.onerror:用于指定连接失败后的回调函数;
  • WebSocket.onmessage:用于指定当从服务器接收到信息时的回调函数;
  • WebSocket.onclose:用于指定连接关闭后的回调函数;

在用户点击进入聊天室时,根据 Vue 绑定的事件,会执行上面的代码,发起 WebSocket 连接,服务端会将相关信息通过 WebSocket 长连接返回给客户端,客户端通过 WebSocket.onmessage 回调进行处理。

得益于 Vue 的双向绑定,在数据显示、事件绑定等方面,处理起来很方便。

关于前端的实现,这里有几点提醒下读者:

  • Vue 默认的分隔符是 {{}},和 Go 的一样,避免冲突进行了修改;
  • WebSocket 有两个方法:send 和 close,一个用来发送消息,一个用于主动断开链接;

server端

代码展示

获取容器日志(conn.go)

package docker

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"io"
	"log"
)
func Conn() io.Reader {
//创建连接
	client, err := client.NewClientWithOpts(client.WithHost("tcp://10.0.0.20:2375"))
	if err != nil {
		log.Println(err)
	}
	//使用连接获取容器日志,返回一个io.Reader
	logs, err := client.ContainerLogs(context.TODO(), "xenodochial_blackburn", types.ContainerLogsOptions{
		ShowStdout: true,
		ShowStderr: true,
		Follow:     true,
	})
	return logs
}

方法 client.ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions)返回一个io.Reader和错误,第一个参数为上下文,第二个参数为容器id或者容器名称,第三个参数是容器日志选项结构体,

type ContainerLogsOptions struct {
   ShowStdout bool // 是否返回日志从stdout 默认false
   ShowStderr bool //  是否返回日志从stderr 默认false
   Since      string // 从这个时间返回日志,时间类型为unix timestamp
   Until      string // 返回这个时间前的日志,时间类型为unix timestamp
   Timestamps bool // 是否在日志行前显示时间戳,默认false
   Follow     bool // 是否返回日志流,默认false
   Tail       string // 返回日志行数,默认为all
   Details    bool 
}

main.go

package main

import (
	"bufio"
	"github.com/gin-gonic/gin"
	"kuludi-websocket/docker"
	"log"
	"net/http"
	"nhooyr.io/websocket"
	"nhooyr.io/websocket/wsjson"
)
func main() {
	r := gin.Default()
	r.LoadHTMLGlob("html/*")

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	r.GET("/ws", func(c *gin.Context) {
    //创建websocker连接
		conn, err := websocket.Accept(c.Writer, c.Request, nil)
		if err != nil {
			log.Println("websocket accept error: ", err)
			return
		}
    //获取容器日志的io.Reader
		reader := docker.Conn()
    //bufio新建Reader
		r := bufio.NewReader(reader)
    
		for {
      //循环从reader中根据换行符读取并转换为string
			s, err := r.ReadString('n')
			if err != nil {
				log.Println("read err: ", err)
			}
      //发送数据
			err = wsjson.Write(c.Request.Context(), conn, &s)
			if err != nil {
				log.Println("wsjson.writer err: ", err)
			}
		}
	})
	r.Run()
}

访问测试

访问http://localhost:8080

在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>