如何实现Web应用、网站状态的监控?
如何实现Web应用、网站状态的监控?
- 关键词:网站监控,服务器监控,页面性能监控,用户体验监控
- 本文通过代码分析、网站应用介绍网站状态监控的方式
- 下文主要分为网站应用、技术实现两部分
一、网站应用
- 现在网络上已经存在一些Web网站监控的服务,虽然功能五花八门,但限制较大,需付费使用
- 本文介绍的技术运行网站见下方地址,不会关闭,可以直接使用
- 一个朴实无华且免费的WEB网站监控工具
- 先看下效果

1. 打开网站
- 【传送门】
https://www.xujian.tech/monitor
2. 微信扫码登录
- 这里通过微信扫码取得小程序openid,利用openid标记用户,不涉及隐私

- 扫码完成后会自动跳转到系统
3. 进入监控表
- 进入系统后,选中左侧菜单进入监控表页面

4. 添加监控器
- 监控器支持POST、GET两种请求方式
- GET请求时,如有参数,请直接放置在地址中
- POST请求时,如有参数,请在表单中填写JSON键值对对象
- Header如果有需要,也可按JSON对象方式填写
- 仅需如下三步,即可完成设置
- 提交后,点击刷新即可在页面上看到监控器记录(此时还未执行)

5. 说明和操作
5.1 关于成功率
- 初次时显示“未执行”,执行正确计算
5.2 关于监控频率
- 每次执行完成计算下一次执行时间,默认30分钟一次(免费用户暂不支持自定义频率)
- 计时器每5分钟执行一次,发现监控器执行时间小于当前时间的,就执行请求
- 所以监控频率并非严格按照30分钟一次
5.2 相关操作
- 新增/编辑监控器后,可以点击“立即执行”进行一次请求,观察设置是否正确
- 需要修改时,可点击“编辑”按钮对监控器内容进行修改
- 点击运行记录,可查看近期运行的情况
- 运行记录中,点击结果复制,可以复制运行的结果(当返回内容大于512b的时候,只存储前512个内容)
- 需要邮件通知的用户,可点击右上角头像设置邮箱,在系统异常的时候,会通过邮件进行提示,邮件内容如下:

6. 功能拓展
- 如果有更多建议、合作,请在本文下方留言
- 或按网站提示添加作者
二、技术实现
1. 技术栈
- 实现一个监控器需前端、后端、数据库、缓存等技术
- 本站主要应用了以下技术:
| 序号 | 技术 | 所属端 |
|---|---|---|
| 1 | VUE | 前端 |
| 2 | Vue Element Admin | 前端 |
| 3 | Java | 后端 |
| 4 | MySQL 数据库 | 后端 |
| 5 | Redis缓存 | 后端 |
| 6 | Nginx | 运维 |
| 7 | MyBaits-plus | 后端 |
2. 核心代码
- 实现web应用监控的核心是定期按规则进行请求,并将结果记录,遇到错误时发送邮件提醒
- 本文以在Spring Boot中实现为例,除Spring Boot基础依赖外,还需添加如下依赖
<!--发送邮件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!--糊涂工具,实现网络请求、工具类等--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.0</version></dependency>
2.1 监控器实体
- 记录监控器基本属性、执行时间、统计结果等
- 下方代码含实体和下次执行时间计算方法
@Data
@Builder
@TableName("m_monitor")
public class MMonitor {@JsonFormat(shape = JsonFormat.Shape.STRING)private Long id;//监控器名称private String name;//创建时间private Date createdAt;//下次运行时间,定时器筛选时的重要指标private Date nextRunAt;//上次运行时间private Date lastRunAt;//计时器类型,1=分钟,2=小时,3=天private Integer timerType;//是否已伤处,1=已删除,0=正常private Integer isDeleted;//计时器步长,整数值private Integer timerLength;//监控器状态,1可用,0停用private Integer status;//用户微信小程序openidprivate String openid;//请求URLprivate String toUrl;//请求方法,GET、POSTprivate String toMethod;//请求参数,JSON Objectprivate String toParams;//请求header,JSON Objectprivate String toHeaders;//返回结果包含为成功,当toResultCode不等于200的时候生效private String toResult;//返回结果code为成功,200表示用code,其他表示包含字符串private Integer toResultCode;//POST请求体格式,0=json,1=formprivate Integer toBodyType;// 最新一次运行情况:1正常,0异常private Integer runStatus;// 最新一次运行情况中文,成功、失败、失败原因private String runResult;// 运行成功次数private Integer countSucceed;// 总运行次数private Integer countAll;//分钟数最短步长,即最短30分钟一次private static final int MIN_MINUTE_LENGTH = 30;// 下次执行时间计算方法public void calNextRunAt(){if(this.lastRunAt == null){this.lastRunAt = new Date();}timerType = timerType == null ? 1 : timerType;if(this.timerLength == null || this.timerLength < 1){this.timerLength = 30;}int addMinute = 0;switch (timerType){case 1:addMinute = timerLength;break;case 2:addMinute = 60 * timerLength;break;case 3:addMinute = 60 * 24 * timerLength;break;}addMinute = Math.max(addMinute,MIN_MINUTE_LENGTH);this.nextRunAt = new Date(System.currentTimeMillis() + 1000L * 60 * addMinute);}
}
2.2 计时器
- 利用Spring Boot的Scheduled定时器实现
@Component
@Slf4j
public class MonitorTimerTask {@ResourceMMonitorMapper monitorMapper;@AutowiredMonitorService monitorService;@Scheduled(cron="0 0/5 * * * *")public void exec(){List<MMonitor> monitorList = monitorMapper.selectList(new LambdaQueryWrapper<MMonitor>().isNotNull(MMonitor::getNextRunAt).lt(MMonitor::getNextRunAt,DateUtil.formatDateTime(new Date())).eq(MMonitor::getStatus,1).eq(MMonitor::getIsDeleted,0));log.info(String.format("符合执行条件的监控器有%d个", monitorList.size()));for (MMonitor mMonitor : monitorList) {monitorService.run(mMonitor);}}
}
- 定时器不生效?记得在SpringBootApplication上添加注解:@EnableScheduling
2.3 按规则进行请求
- 即按监控器的toXX字段配置的内容填充请求参数,进行请求!
- 本段不多说,直接上代码
/*** 运行监控器的方法实现,运行从这里开始* */@Overridepublic void run(MMonitor monitor) {long timestamp = System.currentTimeMillis();if(monitor.getIsDeleted() != null && monitor.getIsDeleted() == 1){return;}Date date = new Date();boolean isSucceed = false;String resultMsg = "成功";String requestResult = "";int code = 0;try{HttpResponse httpResponse = null;if(monitor.getToMethod() != null && monitor.getToMethod().equalsIgnoreCase("GET")){HttpRequest httpRequest = HttpRequest.get(monitor.getToUrl());setHeaders(httpRequest,monitor);httpResponse = httpRequest.execute(false);}else{HttpRequest httpRequest = HttpRequest.post(monitor.getToUrl());setHeaders(httpRequest,monitor);setPostParams(httpRequest,monitor);httpResponse = httpRequest.execute(false);}code = httpResponse.getStatus();requestResult = httpResponse.body();if(monitor.getToResultCode() == 200){isSucceed = code == 200;if(!isSucceed){throw new Exception("返回结果HTTP CODE不为200");}}else {isSucceed = requestResult.contains(monitor.getToResult());if(!isSucceed){throw new Exception("返回结果缺少包含内容");}}}catch (Exception e){isSucceed = false;resultMsg = e.getMessage();}if(isSucceed){monitor.setCountSucceed(monitor.getCountSucceed() + 1);}monitor.setCountAll(monitor.getCountAll() + 1);monitor.setRunStatus(isSucceed ? 1 : 0);monitor.setRunResult(resultMsg);monitor.calNextRunAt();monitor.setLastRunAt(date);monitorMapper.updateById(monitor);timestamp = System.currentTimeMillis() - timestamp;log.info(monitor.getName() + String.format("检查完毕,耗时%dms.", timestamp));if(requestResult != null && requestResult.length() > 512){requestResult = requestResult.substring(0,511) + "...";}MRunRecord runRecord = MRunRecord.builder().monitorId(monitor.getId()).runCode(code).runResult(requestResult).runAt(date).timeSpent(timestamp).openid(monitor.getOpenid()).runStatus(isSucceed ? 1: 0).build();mRunRecordMapper.insert(runRecord);sendEmail(runRecord,monitor);}/*** 发送邮件* */private void sendEmail(MRunRecord runRecord,MMonitor monitor){if(runRecord.getRunStatus() != null && runRecord.getRunStatus() == 1){return;}new Thread(() -> {MUser user = userMapper.selectOne(new LambdaQueryWrapper<MUser>().eq(MUser::getOpenid,runRecord.getOpenid()).orderByDesc(MUser::getId).last(" LIMIT 1"));if(user == null || StrUtil.isBlank(user.getEmail()) || user.getEmail().length() < 5 || !user.getEmail().contains("@")){return;}String subject = "【亚特技术Web监控】【监控异常】" + monitor.getName();String text ="----------------详情登录网站查看----------------\n" +"-------------------请求内容-------------------\n" +"URL:" + monitor.getToUrl() + "\n" +"Method:" + monitor.getToMethod() + "\n" +"-------------------返回内容-------------------\n" +"HttpCode:" + runRecord.getRunCode() + "\n" +"Result:" + runRecord.getRunResult() + "\n";eMailUtils.sendTextMailMessage(user.getEmail(), subject, text);}).start();}/*** 分析规则设置Post参数* */private void setPostParams(HttpRequest httpRequest,MMonitor monitor){if(monitor.getToBodyType() != null && monitor.getToBodyType() == 1){//application/json 方式请求httpRequest.contentType("application/x-www-form-urlencoded;charset=GBK");try{if(!JSONUtil.isTypeJSONObject(monitor.getToParams())){return;}JSONObject joParams = new JSONObject(monitor.getToParams());Map<String, Object> paramsMap = new HashMap<>();for (String key : joParams.keySet()) {paramsMap.put(key,joParams.getStr(key));}httpRequest.form(paramsMap);}catch (Exception e){}}else if(monitor.getToBodyType() != null && monitor.getToBodyType() == 0){httpRequest.contentType("application/json");httpRequest.body(monitor.getToParams());}}/*** 分析规则设置header* */private void setHeaders(HttpRequest httpRequest,MMonitor monitor){try{if(!JSONUtil.isTypeJSONObject(monitor.getToHeaders())){return;}JSONObject joHeader = new JSONObject(monitor.getToHeaders());Map<String,String> headerMap = new HashMap<>();for (String key : joHeader.keySet()) {headerMap.put(key,joHeader.getStr(key));}httpRequest.addHeaders(headerMap);}catch (Exception e){}}
三、结尾说明
- 第一部分说的网站已经可用了,欢迎试用、欢迎长期使用、欢迎联系合作、欢迎定制功能
- 第二部分给出了核心内容,但这部分实际上不是实现整个网站最耗时的:前端开发工作也是费力不讨好的
- 本人同时还提供Java开发一对一教学,有需要的添加微信:xujian_cq详聊
- 欢迎点赞、收藏、评论
相关文章:
如何实现Web应用、网站状态的监控?
如何实现Web应用、网站状态的监控? 关键词:网站监控,服务器监控,页面性能监控,用户体验监控本文通过代码分析、网站应用介绍网站状态监控的方式下文主要分为网站应用、技术实现两部分 一、网站应用 现在网络上已经存在一些Web网站监控的服务ÿ…...
手撕排序之堆排序
一、概念: 什么是逻辑结构、物理结构? 逻辑结构:是我们自己想象出来的,就像内存中不存在一个真正的树 物理结构(存储结构):实际上在内存中存储的形式。 堆的逻辑结构是一颗完全二叉树 堆的物理结构是一个数组 之…...
【奇想星球】重磅!我们的AIGC共创社区平台上线了!
文章目录 01 前言功能模块 02 相识缘起连接价值平台优势 03 奇想星球04 我们做了什么时间线 05 初心愿景06 可爱的小伙伴们后续开发及招募计划 07 结语 公众号原文链接 01 前言 2023年9月10日,我们的平台网站上线了! 奇想星球 | AIGC共创社区平台。网站地…...
2023年数维杯数学建模B题节能列车运行控制优化策略求解全过程文档及程序
2023年数维杯数学建模 B题 节能列车运行控制优化策略 原题再现: 在城市交通电气化进程快速推进的同时,与之相应的能耗增长和负面效应也在迅速增加。城市轨道交通中的快速增长的能耗给城轨交通的可持续性发展带来负担。2018 年,北京、上海、…...
Python--测试代码
目录 1、使用pip安装pytest 1.1 更新pip 1.2 安装putest 2、测试函数 2.1 单元测试和测试用例 2.2 可通过的测试 2.3 运行测试 2.4 未通过的测试 2.5 解决测试未通过 2.6 添加新测试 3、测试类 3.1 各种断言 3.2 一个测试的类 3.3 测试AnonymousSurvey类 3.4 使…...
CentOS 系列版本搭建 Nginx 服务
目录 Nginx 介绍 Nginx 安装 CentOS 系列版本 Nginx 删除 CentOS 系列版本 Nginx 介绍 Nginx 是一个广泛使用的Web服务器和反向代理服务器。 反向代理和负载均衡:Nginx支持反向代理和负载均衡,能够分发请求到多个后端服务器,提高了可用性…...
目标检测YOLO实战应用案例100讲-基于机器视觉的输电线路小目标检测和缺 陷识别(下)
目录 3.3.1 输电线路所有尺寸目标检测性能对比 3.3.2 输电线路小目标检测性能对比...
argparse--命令行参数解析库
文章目录 位置参数help ->描述信息type -> 被转换的类型 可选参数action ->动作基本类型 (store_true)短选项 结合位置参数和可选参数choiceaction ->动作基本类型 (count)default -> 默认值 argparse模块使编写用户友好的命令行变得容易 接口。程序定义了它需要…...
elasticsearch4-文档操作
个人名片: 博主:酒徒ᝰ. 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来。 本篇励志:三人行,必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》,SpringCloud…...
阿里云服务器上CentOS 7.6使用rpm包安装MySQL 8.0.31
我这里下载的是最新版本,需要到MySQL官网最新版本下载地址。 要是想要下载以前的版本需要到MySQL以前版本网址中。 1)先使用wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.31-1.el7.x86_64.rpm-bundle.tar(这个网址现在已经不…...
redis未授权漏洞
redis未授权漏洞是什么? Redis 默认情况下会绑定在 0.0.0.0:6379,这样将会将 Redis 服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取 Redis的数据 它有什么危…...
详解3dMax中渲染线框的两种简单方法
在3dMax中渲染线框是你在某个时候想要完成的事情,例如为了演示分解步骤,或是仅仅为了在模型上创建线框覆盖的独特效果。为三维模型渲染线框最常见的原因是能够在模型上显示干净的拓扑。这篇文章将带你了解在3dMax中渲染三维模型线框的两种最常见、最简单…...
Git - Git 工作流程
文章目录 Git WorkFlow图解小结 Git WorkFlow Git Flow是一种基于Git的工作流程,确实利用了Git作为分布式版本控制系统的优势。 本地代码库 (Local Repository): 每个开发者都维护自己的本地代码库,这是Git分布式性质的体现。本地代码库包含了完整的项目…...
ARM如何利用PMU的Cycle Counter(时钟周期)来计算出CPU的时钟频率
本章将学习如何利用ARM PMU的Cycle Counter,来计算出CPU的时钟周期,从而计算出CPU的时钟频率。在介绍计算方法前,有必要先介绍下什么是时钟周期、机器周期以及指令周期。 如何计算出CPU的时钟频率 一,时钟周期,机器周…...
56资源网系统源码搭建知识付费-含源码
内置了上万条数据资源 大致功能: 支持免费与付费(增加了插件付费插件)支持侧边栏支持添加各类型广告(你所能用到的基本都有).支持网盘下载模块支持所有页面自定义支持文章页三方跳转支持添加页面支持自定义采集&#…...
【运营版】仿东郊到家上门服务app小程序开发同城美容家政预约推拿足浴SPA技师派单源码
套餐一:源码=小程序端+公众号端+APP端=280元 套餐二:全包服务 包服务器+域名+APP+认证小程序+H5+PC=1000元 后端:系统后端使用PHP语言开发 前端:前端使用uniapp进行前后端分离开发 用户端功能模块:技师选择 预约服务 优惠券 订单 技师服务...
uniapp项目实践总结(十五)使用websocket实现简易聊天室
导语:在一些社交软件中,经常可以看到各种聊天室的界面,接下来就总结一下聊天室的原理个实现方法,最后做一个简易的聊天室,包括登录/登出、加入/离开房间、发送接收聊天消息等功能。 目录 准备工作原理分析组件实现实战演练服务端搭建案例展示准备工作 在pages/index文件夹…...
论文阅读之Learning and Generalization of Motor Skills by Learning from Demonstration
论文阅读其实就是用自己的话讲一遍,然后理解其中的方法 0、论文基本信息 为什么阅读此篇论文:因为它是DMP经典论文,被引多次,学史可以明智,了解最初机理。 论文题目:Learning and Generalization of Moto…...
SpringCloud中的Eureka的集群配置
微服务框架中最为重要的就是注册中心,如果只是单注册中心,一旦出现问题,容易导致整个微服务环境不可用,所以建议注册中心集群。 目前SpringCloud框架中使用Eureka作为注册中心,本文简单介绍一下Eureka的集群配置&…...
10 Ubuntu下配置STMCubeMX与CLion IDE联合环境搭建(不包含下载CLion的教程)
序言 果然作为一名测控系的学生,纯搞视觉多少还是有点与专业脱节,决定入坑嵌入式。选择STM32进行入门,并且使用CubeMX加CLion作为我的第一个真正意义上的嵌入式开发环境(大一的时候玩过一段时间,但是没什么技术&#…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
