quartz监控日志(一)
最近几个月,现网总是出现定时器不执行的情况,或者定时器卡死的情况,而又不方便排查,只能依靠quartz的debug日志以及错误日志来监控定时器的执行情况,并且随着我们系统中job越来越多,而使得job问题越来越难以跟踪,所以我们才需要一个能过对定时器进行监控的功能,并能实现线程阻塞告警,以及杀死阻塞线程的功能。
监控job有几种方案:
方案一:通过jmx远程或者直接在应用内部定时获取quartz执行信息,可以新增、修改job、job触发器以及执行情况,但是无法对以前执行的job进行跟踪。
方案二:在job的实现类中记录日志,这个方案太麻烦,因为系统目前有很多job实现类,不可能每个都去添加日志。
方案三:代理job执行类,在初始化时使用代理job执行器。
最后我选择了方案三。
先让我们来分析下源码,目前只针对quartz1.6.0:
首先查看JobRunShell类,这个是定时器的执行类实现了Runnable接口,它有两个空方法如下:
public class JobRunShell implements Runnable {
public void run() {
//省略若干代码
try {
begin();
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job ("
+ jec.getJobDetail().getFullName()
+ ": couldn't begin execution.", se);
break;
}
//省略若干代码
try {
complete(true);
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job ("
+ jec.getJobDetail().getFullName()
+ ": couldn't finalize execution.", se);
continue;
}
}
protected void begin() throws SchedulerException {
}
protected void complete(boolean successfulExecution)
throws SchedulerException {
}
}
很明显,这里预留了两个方法来监控job的执行情况。
所以我们创建了一个其子类来代理它,在开始时记录日志,结束时更新日志,
public class MonitorJobRunShell extends JobRunShell {
/**
* 创建一个新的实例 JobRunShellImpl.
* @param jobRunShellFactory
* @param scheduler
* @param schdCtxt
*/
public MonitorJobRunShell(JobRunShellFactory jobRunShellFactory, Scheduler scheduler, SchedulingContext schdCtxt) {
super(jobRunShellFactory, scheduler, schdCtxt);
}
@Override
protected void begin() throws SchedulerException {
super.begin();
try {
JobDetail jobDetail = jec.getJobDetail();
quartzLog=getService().insert(jobDetail.getName());
} catch (Exception e) {
logger.error("记录job开始时间异常",e);
}catch (Throwable e) {
logger.error("记录job开始时间出错",e);
}
}
@Override
protected void complete(boolean successfulExecution) throws SchedulerException {
super.complete(successfulExecution);
try {
quartzLog.setExeTime(jec.getJobRunTime());
getService().update(quartzLog);
} catch (Exception e) {
logger.error("记录job结束时间异常",e);
}catch (Throwable e) {
logger.error("记录job结束时间出错",e);
}
}
}
创建了该类,必须要让quartz使用我们创建的代理类,这里quartz使用了简单工厂模式,如下
public interface JobRunShellFactory {
/**
* <p>
* Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>
* to obtain instances of <code>{@link JobRunShell}</code>.
* </p>
*/
JobRunShell borrowJobRunShell() throws SchedulerException;
}
我们只需要实现该接口,代理原有的std工厂类:
public class StdJobRunShellFactoryProxy implements JobRunShellFactory{
/**
* <p>
* Called by the <class>{@link org.quartz.core.QuartzSchedulerThread}
* </code> to obtain instances of <code>
* {@link org.quartz.core.JobRunShell}</code>.
* </p>
*/
public JobRunShell borrowJobRunShell() throws SchedulerException {
return new MonitorJobRunShell(this, scheduler, schedCtxt);
}
/**
* <p>
* Called by the <class>{@link org.quartz.core.QuartzSchedulerThread}
* </code> to return instances of <code>
* {@link org.quartz.core.JobRunShell}</code>.
* </p>
*/
public void returnJobRunShell(JobRunShell jobRunShell) {
jobRunShell.passivate();
}
}
进行到这里,需要使用到我们的工厂代理类,这时候则需要代理入口,即StdSchedulerFactory,
public class StdSchedulerFactoryProxy extends StdSchedulerFactory {
/**
* 初始化Scheduler
* 同时,替换JobRunShellFactory,并启动清理job日志线程
* @see org.quartz.impl.StdSchedulerFactory#instantiate(org.quartz.core.QuartzSchedulerResources, org.quartz.core.QuartzScheduler)
*/
protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) {
SchedulingContext schedCtxt = new SchedulingContext();
schedCtxt.setInstanceId(rsrcs.getInstanceId());
Scheduler scheduler = new StdScheduler(qs, schedCtxt);
try {
JobRunShellFactory jobFactory=new StdJobRunShellFactoryProxy();
jobFactory.initialize(scheduler, schedCtxt);
rsrcs.setJobRunShellFactory(jobFactory);
} catch (SchedulerConfigException e) {
logger.error("初始化MonitorStdJobRunShellFactory出错",e);
}
return scheduler;
}
}
最后在初始化Scheduler时使用我们代理的Scheduler工厂类就行,实例如下:
StdSchedulerFactory factory = new StdSchedulerFactoryProxy();
这里我们就实现了自己的quartz监控程序,日志记录方式可以自己扩展。这样可以有效方便的监控job的执行情况,日志中可以记录job的执行时长、线程id等,可以配置阈值如果超时可以在界面上kill该线程。
quartz监控日志(一)的更多相关文章
- 学习总结 之 WebApi服务监控 log4net记录监控日志
在请求WebApi 的时候,我们更想知道在请求数据的时候,调用了哪个接口传了什么参数过来,调用这个Action花了多少时间,有没有人恶意请求.我们可以通过记录日志,对Action进行优化,可以通过日志 ...
- log4net 记录MVC监控日志
由于MVC自身的特点,可以让我们记录每一个Controller下Action的执行时间以及View视图渲染完成的时间,本文采用log4net记录MVC每个Action的执行时间和View视图渲染完成时 ...
- zabbix监控日志文件
环境: 操作系统:centos 6.8 ,zabbix软件版本:zabbix 3.0.1 前提条件:zabbix客户端已经配置了主动模式,如何配置主动模式,请参考此文 监控日志keys 首先要了解k ...
- linux 判断文件最后更新时间 实现监控日志是否有输出功能
linux 判断文件最后更新时间 实现监控日志是否有输出功能. 需求:监控log.txt日志文件,超过一分钟没输出内容就认为是停了,则自动启动程序. 用stat 可以看文件的更新时间stat -c % ...
- zabbix 3.x 监控日志文件
1.启用zabbix主动模式 在zabbix agent端,修改/etc/zabbix/zabbix_agentd.conf ServerActive=服务端IP Hostname=tspnginx0 ...
- C# 面向切面编程--监控日志记录方案
背景:现在公司整体在做监控平台,要求把各个部分的细节都记录下来,在前台页面上有所显示,所以现在需要做的就是一个监控日志的记录工作,今天讲的就是渲染监控日志的例子. 现状:当前的渲染程序没有为监控日志记 ...
- (72)zabbix监控日志文件 MySQL日志为例
一般情况下,日志最先反映出应用当前的问题,在海量日志里面找到我们异常记录,然后记录下来,并且根据情况报警,大家可以监控系统日志.nginx.Apache.业务日志. 这边我拿常见的MySQL日志做监控 ...
- 1.8-1.10 大数据仓库的数据收集架构及监控日志目录日志数据,实时抽取之hdfs系统上
一.数据仓库架构 二.flume收集数据存储到hdfs 文档:http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#hd ...
- 基于sentry的前端错误监控日志系统(部署sentry服务器/前端项目部署)-让前端最快的定位到生产问题
背景 在这越来越发达的网络时代,web应用也是越来越复杂,尤其是前端的开发,也是越来越受重视. 所以在我们前端开发完成后,会有一些列的web应用的上线验证,如自测.QA测试.code review 等 ...
- 写一个nginx监控日志
下面的代码是实现一个nginx监控日志功能,是不是很好玩呢.
随机推荐
- 这几个必备的vscode插件,你安装了几个
作为一名前端开发者,vscode想必大家应该都接触过,就像大多数 IDE 一样,VSCode 也有一个扩展和主题市场,包含了数以千计质量不同的插件. 作为一名熟练掌握各种前端开发工具安装和卸载的大师兄 ...
- Jenkins构建项目遇到的问题总结
4.2.1 在Windows下,Jenkins运行python项目 https://www.jianshu.com/p/f6edbaaa8a0d 4.2.2 配置不同类型的项目的操作步骤 http ...
- Kubernetes(K8s)之Pod
Pod介绍 Pod是K8s的最小调度单位 内部是一组Container容器,根容器Pause和其他业务容器 拥有唯一Pod IP 小贴士: 在生产环境中,极少单独Pod的情况 一般都是使用Deploy ...
- RSA非对称加密算法中的密钥对生成与传输
PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全.密码学.联邦学习.同态加密等隐私计算领域的技术和内容. RSA(Rivest–Shamir–Adleman)加密算法是一 ...
- ZYNQ:Linux添加I2C-RTC驱动
硬件情况 使用的是DS1338这款RTC时钟芯片,I2C总线对应到PS端的I2C1. 配置 内核 添加有关的驱动: 因为DS1338用的驱动与DS13307相似,一找发现是同一个配置. CONFIG_ ...
- React Lazy 和 Suspense
在React应用中,有些组件可能不经常用到,比如法律条款的弹窗,我们几乎不看,这些组件也就没有必要首次加载,可以在点击它们的时候再加载,这就需要动态引入组件,需要组件的时候,才引入组件,加载它们,进行 ...
- nuxt3正确使用keepalive页面缓存组件缓存
最近使用nuxt@3.x版本做SEO优化项目比较多,之前也踩坑过,所以记录一下在 nuxt3 中路由缓存的正确使用方法,本人也之前在GitHub社区中提交过反馈问题,最后是在 3.8.2 版本解决了路 ...
- 全网最适合入门的面向对象编程教程:02 类和对象的Python实现-使用Python创建类
全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类 摘要 本文主要介绍了串口通信协议的基本概念.串口通信的基本流程.如何使用 Python 语言创建一个 ...
- 解决方案 | pywintypes.com_error: (-2147221005, '无效的类字符串', None, None) --Python连接CAD报错真正解决思路!
1 背景 import pythoncom import win32com.client import math wincad = win32com.client.Dispatch("Aut ...
- Django查询特定条件的数据并插入其他表格模型
要将特定 wk_nu 值对应的数据批量插入到 MPS005D3Model 中,你可以执行以下步骤: 确定要插入的 wk_nu 值. 获取与该 wk_nu 相关的数据. 将获取的数据逐一创建为 MPS0 ...