当前位置: 首页 > news >正文

springboot websocket 持续打印 pod 日志

springboot 整合 websocket 和 连接 k8s 集群的方式参考历史 Java 专栏文章

  1. 修改前端页面
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Java后端WebSocket的Tomcat实现</title><script type="text/javascript"></script>
</head><body>
<div></div>
Welcome<br/>
<div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif('WebSocket' in window) {//改成你的地址// websocket = new WebSocket("ws://localhost:8080/api/websocket/100");websocket = new WebSocket("ws://localhost:8080/api/websocket/pod/mm-httpbin-b549bdf48-l2fjp/container/mm-httpbin");} else {alert('当前浏览器 Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function() {setMessageInnerHTML("WebSocket连接成功");}var U01data, Uidata, Usdata//接收到消息的回调方法websocket.onmessage = function(event) {console.log(event.data);setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭WebSocket连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;websocket.send('{"msg":"' + message + '"}');setMessageInnerHTML(message + "&#13;");}
</script></html>
  1. 修改 websocket 类

命名空间测试写死了,需要可以调整

package com.vazquez.k8sclient.websocket;import com.vazquez.k8sclient.util.K8sClient;
import io.kubernetes.client.PodLogs;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.util.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;/*** @Description* @Author vazquez* @DATE 2024/4/10 8:50*/@Slf4j
@Service
@ServerEndpoint("/api/websocket/pod/{podName}/container/{containerName}")
public class PodLogWebsocket {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。private static CopyOnWriteArraySet<PodLogWebsocket> podLogWebsocket = new CopyOnWriteArraySet<PodLogWebsocket>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;private static final ExecutorService executorService = Executors.newCachedThreadPool();private static final int RECENT_LOG_LINE = 1000;private boolean flag = true;/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("podName") String podName, @PathParam("containerName") String containerName) {this.session = session;podLogWebsocket.add(this);     //加入set中addOnlineCount();           //在线数加1getPodLog(podName, containerName);try {sendMessage("conn_success");log.info("当前在线人数为:" + getOnlineCount());} catch (IOException e) {log.error("websocket IO Exception");}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {podLogWebsocket.remove(this);  //从set中删除subOnlineCount();           //在线数减1//断开连接情况下,更新主板占用情况为释放//这里写你 释放的时候,要处理的业务log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @ Param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {//群发消息for (PodLogWebsocket item : podLogWebsocket) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** @ Param session* @ Param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {PodLogWebsocket.onlineCount++;}public static synchronized void subOnlineCount() {PodLogWebsocket.onlineCount--;}public static CopyOnWriteArraySet<PodLogWebsocket> getWebSocketSet() {return podLogWebsocket;}private void getPodLog(String podName, String containerName) {executorService.execute(() -> {BufferedReader reader = null;InputStream is = null;try {//使用单例创建ApiClientString token = "ey...cJ29w";String url = "https://10.xxx6:6443";ApiClient client = Config.fromToken(url, token, false);Configuration.setDefaultApiClient(client);PodLogs logs = new PodLogs(client);//按时间过滤stream流会有堵塞延迟is = logs.streamNamespacedPodLog("default", podName, containerName, null, RECENT_LOG_LINE, false);reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));String line;//若ws连接已经断开,则不再读取数据输出到前端while (this.flag && this.session != null && this.session.isOpen()) {while ((line = readLineWithTimeout(podName, reader)) != null) {if (this.flag) {System.out.println(line);sendMessage(line);} else {break;}}}} catch (Exception e) {log.error("get container log Exception", e);} finally {try {if (reader != null) {reader.close();}} catch (IOException e) {log.error("reader IOException:{}", e.getMessage());}try {if (is != null) {is.close();}} catch (IOException e) {log.error("InputStreamReader IOException:{}", e.getMessage());}}});}/*** 读取一行bufferedReader数据并返回 堵塞超时返回null** @param bufferedReader* @return*/private static String readLineWithTimeout(String podName, BufferedReader bufferedReader) {Future<String> future;try {future = executorService.submit(() -> {try {return bufferedReader.readLine();} catch (IOException e) {return null;}});String message = future.get(10, TimeUnit.SECONDS);//当pod重启或删除时 由于连接会断开 future会直接返回数据为null 此时会不断请求 业务暂时添加10s休眠if (message == null) {Thread.sleep(10 * 1000);}return message;} catch (TimeoutException e) {// Timeout occurredlog.error(podName + " readLineWithTimeout " + Thread.currentThread().getId(), e);return null;} catch (InterruptedException | ExecutionException e) {e.printStackTrace();return null;}}
}
  1. 效果展示

在这里插入图片描述

相关文章:

springboot websocket 持续打印 pod 日志

springboot 整合 websocket 和 连接 k8s 集群的方式参考历史 Java 专栏文章 修改前端页面 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Java后端WebSocket的Tomcat实现</title><script type"text/javasc…...

C代码编译过程与进程内存分布

C代码编译过程 在这篇文章中&#xff0c;我们将探讨C语言代码的编译流程以及进程在运行时的内存布局。编译过程通常包括几个关键步骤&#xff1a;预处理、编译、汇编和链接。 预处理阶段主要是处理源代码文件中的宏定义、头文件包含和条件编译指令。在此阶段&#xff0c;编译…...

Windows 部署ChatGLM3大语言模型

一、环境要求 硬件 内存&#xff1a;> 16GB 显存: > 13GB&#xff08;4080 16GB&#xff09; 硬盘&#xff1a;60G 软件 python 版本推荐3.10 - 3.11 transformers 库版本推荐为 4.36.2 torch 推荐使用 2.0 及以上的版本&#xff0c;以获得最佳的推理性能 二、部…...

JS相关八股之什么是事件循环

在JavaScript中&#xff0c;“事件循环”&#xff08;Event Loop&#xff09;是一个非常重要的概念&#xff0c;它是指JavaScript引擎如何在单线程中处理异步操作的机制。单线程意味着在任意时刻&#xff0c;JavaScript代码只能执行一个任务。 一.事件循环的工作流程大致如下&…...

SpringCloud集成Skywalking链路追踪和日志收集

1. 下载Agents https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz 2. 上传到服务器解压 在Spring Cloud项目中&#xff0c;每部署一个服务时&#xff0c;就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署…...

HTTP 域名和主机是一回事吗?有了主机和域名,如何建站?

域名不等于主机名&#xff0c;例如baidu.com是一个权威域的域名&#xff0c;但是根本没有一个主机的名字叫做baidu.com,但是dns.baidu.com就是一个主机名&#xff0c;它就是负责baidu.com的服务器的主机名&#xff0c;www.baidu.com也是一个主机名,它是百度web服务器的主机名。…...

运营干货:四个技巧掌握爆款选题方法

在运营工作中&#xff0c;选题是一项至关重要的工作&#xff0c;选对了一个热门话题&#xff0c;就能吸引大量用户的关注和互动&#xff0c;从而取得更好的运营成果。 今天&#xff0c;就给大家分享四个爆款选题方法&#xff0c;让大家的运营更上一层楼&#xff01; 第一种&a…...

柯桥商务口语之怎么样说英语更加礼貌?十个礼貌用语get起来!

当你在国外需要帮助的时候&#xff0c;这些礼貌用语真的是能够帮到你的哦 1.Would/Could you help me? 你可帮助我吗&#xff1f; 相信有些人想请求帮助的时候&#xff0c;一开口就用Can you&#xff0c;这个用在朋友或者熟人上面当然是没有问题的&#xff0c;但是如果是向…...

嵌入式工程师如何摸鱼?

有老铁问我&#xff0c;做嵌入式开发要加班吗&#xff1f; 也不知道搞什么鬼&#xff0c;现在的年轻人对加班这么抵触。 我刚做开发那会&#xff0c;啥也不懂&#xff0c;每天基本都要加班到晚上7-9点不等&#xff0c;我并不抵触加班&#xff0c;因为早早回家&#xff0c;也没什…...

C++语言题库(一)—— 基本知识类

目录 1. Hello World! 2. 据说一个人的标准体重应该是其身高&#xff08;单位&#xff1a;厘米&#xff09;减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高&#xff0c;请你计算其标准体重应该是多少&#xff1f; 3. 给定一个华氏温度F…...

gemini1.5 API调用

https://ai.google.dev/pricing?hlzh-cn 查询可用的model https://generativelanguage.googleapis.com/v1beta/models?keyxxx 使用postman调用 https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?keyxxx https://ai.google…...

C++从入门到精通——const与取地址重载

const与取地址重载 前言一、const正常用法const成员函数问题const对象可以调用非const成员函数吗非const对象可以调用const成员函数吗const成员函数内可以调用其它的非const成员函数吗非const成员函数内可以调用其它的const成员函数吗总结 二、取地址及const取地址操作符重载概…...

手写spring IOC底层源码来模拟spring如何利用多级缓存解决循环依赖的问题

在文章开始之前&#xff0c;先来看一张spring IOC加载过程的脑图吧 Spring IOC的加载过程 首先,当我们去new了一个applicationContext,它底层呢就会把我们配置的bean进行扫描,然后创建成一个一个的beanDefinition放在我们的beanDefinitionMap中,此时就有了一切创造bean的原料信…...

C++11 Thead线程和线程池

参考资料&#xff1a; 2、5.lock_guard 与 std::unique_lock-陈子青的编程学习课堂 (seestudy.cn) 3、C11 多线程编程-小白零基础到手撕线程池_哔哩哔哩_bilibili 一、 C11 Thead线程库的基本使用 # include <thread> std::thread t(function_name, args...); // 线…...

Windows版Apache 2.4.59解压直用(免安装-绿色-项目打包直接使用)

windows下Apache分类 Apache分为 安装版和解压版 安装版: 安装方便&#xff0c;下一步------下一步就OK了&#xff0c;但重装系统更换环境又要重新来一遍&#xff0c;会特别麻烦 解压版&#xff08;推荐&#xff09;&#xff1a; 这种方式&#xff08;项目打包特别方便&#x…...

刀具表面上的微结构

刀具表面微结构通常指在刀具表面对特定功能设计的微观纹理&#xff0c;这些纹理可以是沟槽、凹坑、凸起或任何其他形式的微观图案。这些微结构的设计和应用是为了改善刀具的切削性能&#xff0c;减少切削力和切削温度&#xff0c;提高切削效率和精度&#xff0c;同时降低切削液…...

css3实现微信扫码登陆动画

在做微信扫码登陆时&#xff0c;出现一个背景光图上下扫码动画&#xff0c;用css3图片实现。 实现原理&#xff1a; 1.准备一个渐变的背景.png图 2.css动画帧实现动画 看效果&#xff1a; css代码&#xff1a; #wx-scan{position: absolute;top:0px;left: 50%;z-index: 3;ma…...

vue3 导入excel数据

所需包 "xlsx": "^0.18.5"页面导入包 import * as XLSX from xlsx; import {genFileId, UploadProps, UploadRawFile,ElTable } from element-plus;页面 <el-upload accept".xlsx" :on-change"changeExcel" :on-exceed"ha…...

C# linq 根据多字段动态Group by

实现类&#xff1a; public static class LinqHepler {/// <summary>/// 根据单个字段动态Group/// </summary>/// <typeparam name"T"></typeparam>/// <param name"source"></param>/// <param name"prop…...

C语言学习/复习22----阶段测评编程题

一、阶段测评练习 题1&#xff1a; 题2&#xff1a;...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...