当前位置: 首页 > 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;...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...