gin event source实现k8s pod logs 实时刷新

前端js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="result">

</div>

<div>
    <button type="button" onclick="submit()">提交!</button>
</div>
</body>
<script>
    function submit() {

        const stream = new EventSource("http://localhost:8080/stream?namespace=dev&podName=xxxx&containerName=xxxxxx")
        stream.addEventListener("message", function (e) {
           console.log(e)
           document.getElementById("result").innerHTML += e.data
        });
        stream.addEventListener("stop", function (e) {
            stream.close()
            console.log(e)
        });
        stream.onerror = function (event) {
            stream.close()
            console.log(event)
        }
    }

</script>
</html>

后端go代码

package main

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	cors "github.com/rs/cors/wrapper/gin"
	"io"
	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

const kubeconfig = `
`

type SteamRequest struct {
	Namespace     string `form:"namespace" binding:"required"`
	PodName       string `form:"podName" binding:"required"`
	ContainerName string `form:"containerName" binding:"required"`
}

func setupRouter() *gin.Engine {
	r := gin.Default()

	r.Use(cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{
			http.MethodHead,
			http.MethodGet,
			http.MethodPost,
			http.MethodPut,
			http.MethodPatch,
			http.MethodDelete,
		},
		AllowedHeaders:     []string{"*"},
		AllowCredentials:   true,
		OptionsPassthrough: true,
	}))

	r.GET("/stream", func(c *gin.Context) {
		var request SteamRequest
		err := c.ShouldBindQuery(&request)
		if err != nil {
			log.Fatal(err.Error())
		}
		log.Printf("request: %v \n", request)

		clientConfig, err := clientcmd.NewClientConfigFromBytes([]byte(kubeconfig))
		if err != nil {
			panic(err.Error())
		}
		config, err := clientConfig.ClientConfig()
		if err != nil {
			panic(err.Error())
		}
		// create the clientset
		clientset, err := kubernetes.NewForConfig(config)
		if err != nil {
			panic(err.Error())
		}
		var lines int64 = 100
		stream, err := clientset.CoreV1().Pods(request.Namespace).GetLogs(request.PodName, &v1.PodLogOptions{
			Container:    request.ContainerName,
			Follow:       true,
			Timestamps:   false,
			SinceSeconds: nil,
			SinceTime:    nil,
			TailLines:    &lines,
			Previous:     false,
		}).Stream(context.Background())

		if err != nil {
			return
		}

		chanStream := make(chan string, 100)
		go func() {
			defer stream.Close()
			defer close(chanStream)
			bufReader := bufio.NewReader(stream)
			for {
				line, err := bufReader.ReadString('\n')

				if errors.Is(err, io.EOF) {
					fmt.Println("Stream finished")
					chanStream <- "<!finish>"
					return
				}

				if err != nil {
					fmt.Printf("Stream error: %v\n", err)
					chanStream <- "<!error>"
					return
				}
				chanStream <- line
				fmt.Printf("Stream response: %v\n", line)
			}
		}()

		c.Stream(func(w io.Writer) bool {
			if msg, ok := <-chanStream; ok {
				if msg == "<!finish>" {
					c.SSEvent("stop", "finish")
				}
				if msg == "<!error>" {
					c.SSEvent("stop", "error")
				}
				c.SSEvent("message", msg)
				fmt.Printf("message: %v\n", msg)

				return true
			}
			return false
		})

	})
	return r
}

func main() {
	gin.SetMode(gin.ReleaseMode)
	router := setupRouter()

	srv := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}
	go func() {
		// 服务连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("Shutdown Server ...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 Gin 框架实现接收 POST 方法上传文件的代码: ```go package main import ( "fmt" "io" "net/http" "os" "path/filepath" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.POST("/upload", uploadHandler) router.Run(":8080") } func uploadHandler(c *gin.Context) { file, handler, err := c.Request.FormFile("file") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Error Retrieving the File", }) return } defer file.Close() // 创建路径 err = os.MkdirAll("uploads", os.ModePerm) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("Error Creating Path: %s", err.Error()), }) return } // 保存文件 f, err := os.OpenFile(filepath.Join("uploads", handler.Filename), os.O_WRONLY|os.O_CREATE, 0666) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("Error Saving File: %s", err.Error()), }) return } defer f.Close() io.Copy(f, file) c.JSON(http.StatusOK, gin.H{ "message": "File Uploaded Successfully", }) } ``` 以上代码中,我们使用了 Gin 框架提供的 `gin.Default()` 函数创建了一个默认的路由器,并使用 `router.POST()` 函数定义了一个名为 `/upload` 的路由,其中 `uploadHandler()` 函数处理了该路由的请求。接收上传的文件和判断错误的方式与之前的示例相同,不再赘述。我们使用了 `os.MkdirAll()` 创建了上传文件的保存路径,并使用 `os.OpenFile()` 创建文件,通过 `io.Copy()` 函数将上传的文件内容保存到该文件中。最后,我们使用 `c.JSON()` 函数向客户端发送 JSON 格式的响应。 在这个示例中,我们将上传的文件保存在了名为 `uploads` 的文件夹中,当然,您可以根据实际情况修改文件夹名称和路径。与之前的示例一样,我们使用了 `defer` 关键字延迟关闭打开的文件和文件流,避免资源泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值