Java 定制SMTPAppender中的scheduleAtFixedRate不';不要拖延
当出现异常时,我将对象发送到服务器(顺序约为90),例如端点关闭,Logback会触发自定义STMP appender,它只发送一封最多包含10个日志的电子邮件,然后会出现延迟,并发送其他日志。有没有可能,Java 定制SMTPAppender中的scheduleAtFixedRate不';不要拖延,java,multithreading,spring-boot,scheduler,smtpappender,Java,Multithreading,Spring Boot,Scheduler,Smtpappender,当出现异常时,我将对象发送到服务器(顺序约为90),例如端点关闭,Logback会触发自定义STMP appender,它只发送一封最多包含10个日志的电子邮件,然后会出现延迟,并发送其他日志。有没有可能,start()被频繁调用 问题: scheduler.scheduleAtFixedRate(这个::sendmail,1,1L,TimeUnit.HOURS) 执行一次后不会延迟,直接执行另一次,因此许多电子邮件在一小时内发送 要更改计划程序的延迟,我必须做什么? <configura
start()
被频繁调用
问题:scheduler.scheduleAtFixedRate(这个::sendmail,1,1L,TimeUnit.HOURS)代码>
执行一次后不会延迟,直接执行另一次,因此许多电子邮件在一小时内发送
要更改计划程序的延迟,我必须做什么?
<configuration debug="true">
<!-- Logging per console and per email -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
<!-- sets the format of the output -->
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="EMAIL" class="com.konverto.phonebillasaj.appenders.ScheduledSMTPAppender">
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout" />
<smtpHost>smtp.xxx.net</smtpHost>
<smtpPort>587</smtpPort>
<STARTTLS>true</STARTTLS>
<username>xxx@domain.net</username>
<password>myPass</password>
<to>yyy@domain.net</to>
<from>xxx@domain.net</from>
<maxMessages>10</maxMessages>
<!-- for testing , comment in production, default 256 -->
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- Send just one log entry per email, ready for a lot of emails if you put one. -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
<!-- for testing , comment in production, default asynchronousSending = true -->
<asynchronousSending>false</asynchronousSending>
</appender>
<logger name="com.konverto.phonebillasaj" level="error" additivity="false">
<appender-ref ref="EMAIL"/>
<appender-ref ref="CONSOLE" />
</logger>
<root level="error">
<appender-ref ref="EMAIL" />
<appender-ref ref="CONSOLE" />
</root>
public class ScheduledSMTPAppender extends SMTPAppender {
private final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<ILoggingEvent> events = new ArrayList<>();
private int maxMessages = 10;
public ScheduledSMTPAppender() {
super();
}
public ScheduledSMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) {
super(eventEvaluator);
}
@Override public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
@Override protected void sendBuffer(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent lastEventObject) {
events.add(lastEventObject);
if (events.size() > maxMessages)
{
sendEmail();
}
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()){
return;
}
ILoggingEvent lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
CyclicBuffer<ILoggingEvent> cb;
if (events.isEmpty()) {
cb = new CyclicBuffer<>(1);
} else {
cb = new CyclicBuffer<>(events.size());
for (ILoggingEvent e : events){
cb.add(e);
}
}
super.sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
public String getContentType() {
return layout.getContentType();
}
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
调试后,我注意到将名为[EMAIL]的appender附加到Logger[ROOT]
发生了两次,这可能是问题所在,如果是,我如何解决
洪水图像(如您所见,在一小时内发送了两封电子邮件…
Logback.xml配置:
<configuration debug="true">
<!-- Logging per console and per email -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
<!-- sets the format of the output -->
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="EMAIL" class="com.konverto.phonebillasaj.appenders.ScheduledSMTPAppender">
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout" />
<smtpHost>smtp.xxx.net</smtpHost>
<smtpPort>587</smtpPort>
<STARTTLS>true</STARTTLS>
<username>xxx@domain.net</username>
<password>myPass</password>
<to>yyy@domain.net</to>
<from>xxx@domain.net</from>
<maxMessages>10</maxMessages>
<!-- for testing , comment in production, default 256 -->
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- Send just one log entry per email, ready for a lot of emails if you put one. -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
<!-- for testing , comment in production, default asynchronousSending = true -->
<asynchronousSending>false</asynchronousSending>
</appender>
<logger name="com.konverto.phonebillasaj" level="error" additivity="false">
<appender-ref ref="EMAIL"/>
<appender-ref ref="CONSOLE" />
</logger>
<root level="error">
<appender-ref ref="EMAIL" />
<appender-ref ref="CONSOLE" />
</root>
public class ScheduledSMTPAppender extends SMTPAppender {
private final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<ILoggingEvent> events = new ArrayList<>();
private int maxMessages = 10;
public ScheduledSMTPAppender() {
super();
}
public ScheduledSMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) {
super(eventEvaluator);
}
@Override public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
@Override protected void sendBuffer(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent lastEventObject) {
events.add(lastEventObject);
if (events.size() > maxMessages)
{
sendEmail();
}
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()){
return;
}
ILoggingEvent lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
CyclicBuffer<ILoggingEvent> cb;
if (events.isEmpty()) {
cb = new CyclicBuffer<>(1);
} else {
cb = new CyclicBuffer<>(events.size());
for (ILoggingEvent e : events){
cb.add(e);
}
}
super.sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
public String getContentType() {
return layout.getContentType();
}
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
%d{HH:mm:ss.SSS}[%t]-5级别%logger{36}-%msg%n
测试:%logger{20}-%m
smtp.xxx.net
587
真的
xxx@domain.net
我的通行证
yyy@domain.net
xxx@domain.net
10
1.
假的
附录代码:
<configuration debug="true">
<!-- Logging per console and per email -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
<!-- sets the format of the output -->
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="EMAIL" class="com.konverto.phonebillasaj.appenders.ScheduledSMTPAppender">
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout" />
<smtpHost>smtp.xxx.net</smtpHost>
<smtpPort>587</smtpPort>
<STARTTLS>true</STARTTLS>
<username>xxx@domain.net</username>
<password>myPass</password>
<to>yyy@domain.net</to>
<from>xxx@domain.net</from>
<maxMessages>10</maxMessages>
<!-- for testing , comment in production, default 256 -->
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- Send just one log entry per email, ready for a lot of emails if you put one. -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
<!-- for testing , comment in production, default asynchronousSending = true -->
<asynchronousSending>false</asynchronousSending>
</appender>
<logger name="com.konverto.phonebillasaj" level="error" additivity="false">
<appender-ref ref="EMAIL"/>
<appender-ref ref="CONSOLE" />
</logger>
<root level="error">
<appender-ref ref="EMAIL" />
<appender-ref ref="CONSOLE" />
</root>
public class ScheduledSMTPAppender extends SMTPAppender {
private final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<ILoggingEvent> events = new ArrayList<>();
private int maxMessages = 10;
public ScheduledSMTPAppender() {
super();
}
public ScheduledSMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) {
super(eventEvaluator);
}
@Override public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
@Override protected void sendBuffer(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent lastEventObject) {
events.add(lastEventObject);
if (events.size() > maxMessages)
{
sendEmail();
}
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()){
return;
}
ILoggingEvent lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
CyclicBuffer<ILoggingEvent> cb;
if (events.isEmpty()) {
cb = new CyclicBuffer<>(1);
} else {
cb = new CyclicBuffer<>(events.size());
for (ILoggingEvent e : events){
cb.add(e);
}
}
super.sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
public String getContentType() {
return layout.getContentType();
}
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
public类ScheduledSMTPAppender扩展了SMTPAppender{
专用最终螺纹工厂tf=r->{
线程t=新线程(r,“ScheduledStmpAppender线程”);
t、 setDaemon(true);//创建守护进程,否则将阻止程序退出
返回t;
};
private final ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1,tf);
私有最终列表事件=新建ArrayList();
私有int maxMessages=10;
公共调度DSMTAppender(){
超级();
}
公共计划DSMTAppender(EventEvaluator EventEvaluator){
超级(事件评估员);
}
@重写公共void start(){
super.start();
scheduleAtFixedRate(这个::sendmail,1,1L,TimeUnit.HOURS);
}
@重写受保护的void sendBuffer(CyclicBuffer cb,ILOGingEvent lastEventObject){
添加(lastEventObject);
if(events.size()>maxMessages)
{
sendmail();
}
}
//需要同步以确保线程安全
私有同步的void sendmail(){
试一试{
if(events.isEmpty()){
返回;
}
ilogingevent lastEvent=events.get(events.size()-1);
events.remove(events.size()-1);
CyclicBuffer cb;
if(events.isEmpty()){
cb=新自行车缓冲垫(1);
}否则{
cb=新的CyclicBuffer(events.size());
对于(ILOGINGEVENT e:事件){
cb.添加(e);
}
}
super.sendBuffer(cb,lastEvent);
事件。清除();
}捕获(例外e){
//重要的是要有一个全面的在这里,否则计划的任务将死亡
addError(“发送电子邮件通知时出错。”,e);
}
}
//这允许将“maxMessages”作为appender的参数
public int getMaxMessages(){
返回消息;
}
公共字符串getContentType(){
返回布局。getContentType();
}
公共void setMaxMessages(int-maxMessages){
this.maxMessages=maxMessages;
}
这似乎就是问题所在
@Override
public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}
此计划程序将为每个初始化的附加程序排队sendEmail任务。
您是否可以将对象的实例或某个id与每个日志行一起记录,并且每次调用start时都可以记录?这应该可以澄清该场景
我只是想澄清一下,我使用Sysout而不是logger(并在main方法中初始化)尝试了相同的代码,它按照预期工作
public class ScheduledSMTPAppender /*extends SMTPAppender*/ {
private static final ThreadFactory tf = r -> {
Thread t = new Thread(r, "ScheduledSMTPAppender Thread");
t.setDaemon(true); //make daemon or it will prevent your program to exit
return t;
};
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, tf);
private final List<String> events = new ArrayList<>();
private int maxMessages = 10;
public static void main(String args[]) {
ScheduledSMTPAppender app = new ScheduledSMTPAppender();
System.out.println("started");
Thread t = new Thread(() -> {
try {
scheduler.awaitTermination(1, TimeUnit.HOURS);
} catch (Exception e) {
}
});
System.out.println("awaiting termination");
t.start();
System.out.println("thread initiated");
new Thread(() -> {
// Thread to add events to check logs
for (int i =0;i<10;i++)
{app.addEvent("asd");
try {Thread.sleep(1000);
} catch(Exception e) {};}
}).start();
}
public ScheduledSMTPAppender() {
super();
System.out.println("starting");
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.SECONDS);
}
/*
public ScheduledSMTPAppender(EventEvaluator<String> eventEvaluator) {
super(eventEvaluator);
}
@Override
public void start() {
super.start();
scheduler.scheduleAtFixedRate(this::sendEmail, 1, 1L, TimeUnit.HOURS);
}*/
//@Override
protected void sendBuffer(List<String> cb, String lastEventObject) {
//System.out.println("sending email");
events.add(lastEventObject);
if (events.size() > maxMessages) {
sendEmail();
}
System.out.println(new Date() + "sent email" + lastEventObject);
}
//needs to be synchronized for thread safety
private synchronized void sendEmail() {
try {
if (events.isEmpty()) {
return;
}
String lastEvent = events.get(events.size() - 1);
events.remove(events.size() - 1);
List<String> cb;
if (events.isEmpty()) {
cb = new ArrayList<>(1);
} else {
cb = new ArrayList<>(events.size());
for (String e : events) {
cb.add(e);
}
}
sendBuffer(cb, lastEvent);
events.clear();
} catch (Exception e) {
//Important to have a catch all here or the scheduled task will die
//addError("Error occurred while sending e-mail notification.", e);
}
}
//this allows to make "maxMessages" a parameter of your appender
public int getMaxMessages() {
return maxMessages;
}
// public String getContentType() {
// return layout.getContentType();
// }
public void setMaxMessages(int maxMessages) {
this.maxMessages = maxMessages;
}
public void addEvent(String s) {
events.add(s);
}
}
public类ScheduledSMTPAppender/*扩展了SMTPAppender*/{
专用静态最终线程工厂tf=r->{
线程t=新线程(r,“ScheduledStmpAppender线程”);
t、 setDaemon(true);//创建守护进程,否则将阻止程序退出
返回t;
};
private static final ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1,tf);
私有最终列表事件=新建ArrayList();
私有int maxMessages=10;
公共静态void main(字符串参数[]){
scheduledstmpappender app=新的scheduledstmpappender();
System.out.println(“已启动”);
线程t=新线程(()->{
试一试{
调度程序。等待终止(1,时间单位。小时);
}捕获(例外e){
}
});
系统输出打印号(“等待终止”);
t、 start();
System.out.println(“线程启动”);
新线程(()->{
//线程添加事件以检查日志
对于(int i=0;i maxMessages){
sendmail();
}
System.out.println(新日期()+“已发送电子邮件”+lastEventObject);
}
//需要同步以确保线程安全
私有同步的void sendmail(){
试一试{
if(events.isEmpty()){
返回;
}
字符串lastEvent=events.get(events.size()-1);
events.remove(events.size()-1);
名单cb;
if(events.isEmpty()){
cb=新阵列列表(1);
}否则{
cb=新的ArrayList(events.size());
for(字符串e:事件){
cb.添加(e);
}
}
sendBuffer(cb,lastEvent);
事件。清除();
}捕获(例外e){
//重要的是要有一个全面的在这里,否则计划的任务将死亡
//addError(“发送电子邮件通知时出错。”,e);
}
}
//这允许将“maxMessages”作为appender的参数
public int getMaxMessages(){
返回消息;
}
//公共字符串getContentType(){
//return layout.getCont