How to implement abnormal log alarm in JAVA based on Slack
1. Function introduction
Implementation logic: Under normal circumstances, exceptions will be processed in the code , the most basic thing is to print logs. This article will realize that when printing logs, exception information will be sent to the Slack channel at the same time. Development or operation and maintenance personnel can create a Slack account and join the channel to receive alerts of abnormal information in real time.
2. Introduction to Slack
Slack is a web-based real-time communication tool that can be used as a single application on desktop/laptop computers, mobile devices, and as a web application. Basically, it's your private chat and collaboration room. For many companies, it has replaced email/private forums/chat rooms as the primary internal text-based communication channel.
It can be understood that it is a chat group, large-scale tool integration, file integration, and unified search. As of the end of 2014, Slack has integrated 65 tools and services such as email, text messages, Google Drives, Twitter, Trello, Asana, GitHub, etc., which can bring together various fragmented enterprise communication and collaboration. Several important concepts:
Workspace: Quite a workspace. Users can join or create different workspaces. Many times, the name and URL of the workspace will be the company name.
Channel: Channels can be divided into different teams or topics, and can also be understood as equivalent to WeChat, where members in the channel share information in the channel.
3. Early preparation
slack configuration
Create an account and log in. You can use the app or log in to the web version with a browser
Create your own workspace and invite others to join the workspace.
Create a channel and invite colleagues to join. At this time, you can send messages to the channel, and everyone who joins the channel can see the message
Work Add application Incoming WebHook to the area, select the channel, and save the Webhook URL. Later, the Webhook implementation program will be used to send messages to the channel.
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
Copy after login
4. Specific implementation1. Implement Slack to send messagesSlackUtil Send message to Slack tool class<dependencies> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> </dependencies>
package com.yy.operation;
import com.yy.common.CommonThreadFactory;
import com.yy.common.ConnUtil;
import org.apache.commons.lang.StringUtils;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author :Max
* @date :Created in 2022/8/26 下午12:54
* @description:
*/
public class SlackUtil {
private static final Logger logger = Logger.getLogger(SlackUtil.class.getCanonicalName());
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final String SEND_USER_NAME ="运维机器人";
private static int MAX_RETRY =3;
/**
* 线程池 抛弃策略DiscardPolicy:这种策略,会默默的把新来的这个任务给丢弃;不会得到通知
*/
private static ExecutorService executor = new ThreadPoolExecutor(10,30,60,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(200),new CommonThreadFactory("Slack"), new ThreadPoolExecutor.DiscardPolicy());
private static String MSG_FORMAT ="payload='{'"channel": "{0}", "username": "{1}", "text": "{2}", "icon_emoji": ":ghost:"'}'" ;
/**
* 保存的Webhook URL ,需要初始化
*/
private static String WEBHOOK_URL ;
private static boolean SLACK_ABLE;
public static void setSlackConfig(String webhookUrl){
WEBHOOK_URL = webhookUrl;
SLACK_ABLE = true;
}
/**
* slack异步发消息,保证不能影响到主功能
* @param channel
* @param msg
*/
public static void send(final String channel, final String msg){
if(!SLACK_ABLE){
return;
}
if(StringUtils.isBlank(msg)){
return;
}
executor.submit(new Runnable() {
@Override
public void run() {
try {
SlackUtil.send(channel,sdf.format(System.currentTimeMillis())+" "+msg,MAX_RETRY);
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
});
}
/**
* 如果slask发消息失败,会最多尝试发三次,三次都失败,会打印异常信息
* @param channel
* @param msg
* @param retry
* @throws Exception
*/
public static void send(String channel, String msg, int retry) throws Exception {
if(msg.indexOf(""")>=0 ||msg.indexOf("{")>=0 ||msg.indexOf("}")>=0){
msg =msg.replace(""","'").replace("{","[").replace("}","]");
}
String payload = MessageFormat.format(MSG_FORMAT, channel,SEND_USER_NAME,msg);
String result = ConnUtil.getContentByPostWithUrlencode(WEBHOOK_URL,payload);
logger.info("result:"+result);
if(StringUtils.isEmpty(result) ||!result.startsWith("ok")){
--retry;
if(retry>0){
try {
TimeUnit.SECONDS.sleep(retry*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
send(channel,msg,retry);
}else{
throw new Exception("Fail to send slack:"+result+"\nmsg:"+msg);
}
}
}
}
Copy after login
Initiate a request to webhook through Urlencodepackage com.yy.operation; import com.yy.common.CommonThreadFactory; import com.yy.common.ConnUtil; import org.apache.commons.lang.StringUtils; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.concurrent.*; import java.util.logging.Level; import java.util.logging.Logger; /** * @author :Max * @date :Created in 2022/8/26 下午12:54 * @description: */ public class SlackUtil { private static final Logger logger = Logger.getLogger(SlackUtil.class.getCanonicalName()); private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final String SEND_USER_NAME ="运维机器人"; private static int MAX_RETRY =3; /** * 线程池 抛弃策略DiscardPolicy:这种策略,会默默的把新来的这个任务给丢弃;不会得到通知 */ private static ExecutorService executor = new ThreadPoolExecutor(10,30,60,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(200),new CommonThreadFactory("Slack"), new ThreadPoolExecutor.DiscardPolicy()); private static String MSG_FORMAT ="payload='{'"channel": "{0}", "username": "{1}", "text": "{2}", "icon_emoji": ":ghost:"'}'" ; /** * 保存的Webhook URL ,需要初始化 */ private static String WEBHOOK_URL ; private static boolean SLACK_ABLE; public static void setSlackConfig(String webhookUrl){ WEBHOOK_URL = webhookUrl; SLACK_ABLE = true; } /** * slack异步发消息,保证不能影响到主功能 * @param channel * @param msg */ public static void send(final String channel, final String msg){ if(!SLACK_ABLE){ return; } if(StringUtils.isBlank(msg)){ return; } executor.submit(new Runnable() { @Override public void run() { try { SlackUtil.send(channel,sdf.format(System.currentTimeMillis())+" "+msg,MAX_RETRY); } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } } }); } /** * 如果slask发消息失败,会最多尝试发三次,三次都失败,会打印异常信息 * @param channel * @param msg * @param retry * @throws Exception */ public static void send(String channel, String msg, int retry) throws Exception { if(msg.indexOf(""")>=0 ||msg.indexOf("{")>=0 ||msg.indexOf("}")>=0){ msg =msg.replace(""","'").replace("{","[").replace("}","]"); } String payload = MessageFormat.format(MSG_FORMAT, channel,SEND_USER_NAME,msg); String result = ConnUtil.getContentByPostWithUrlencode(WEBHOOK_URL,payload); logger.info("result:"+result); if(StringUtils.isEmpty(result) ||!result.startsWith("ok")){ --retry; if(retry>0){ try { TimeUnit.SECONDS.sleep(retry*5); } catch (InterruptedException e) { e.printStackTrace(); } send(channel,msg,retry); }else{ throw new Exception("Fail to send slack:"+result+"\nmsg:"+msg); } } } }
package com.yy.common;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author :Max
* @date :Created in 2022/8/26 下午1:44
* @description:
*/
public class ConnUtil {
private static final Logger logger = Logger.getLogger(ConnUtil.class.getCanonicalName());
public static String getContentByPostWithUrlencode(String url,String msg){
StringEntity entity = new StringEntity(msg, "UTF-8");
entity.setContentEncoding("UTF-8");
entity.setContentType(" application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(url);
request.setEntity(entity);
HttpResponse response = null;
try {
response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
InputStream instream = responseEntity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
StringBuffer contents = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
contents.append(line);
contents.append("\n");
}
return contents.toString();
}
} catch (Exception ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
return null;
}
}
Copy after login
SlackUtil testpackage com.yy.common; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.logging.Level; import java.util.logging.Logger; /** * @author :Max * @date :Created in 2022/8/26 下午1:44 * @description: */ public class ConnUtil { private static final Logger logger = Logger.getLogger(ConnUtil.class.getCanonicalName()); public static String getContentByPostWithUrlencode(String url,String msg){ StringEntity entity = new StringEntity(msg, "UTF-8"); entity.setContentEncoding("UTF-8"); entity.setContentType(" application/x-www-form-urlencoded"); HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost request = new HttpPost(url); request.setEntity(entity); HttpResponse response = null; try { response = httpClient.execute(request); HttpEntity responseEntity = response.getEntity(); if (responseEntity != null) { InputStream instream = responseEntity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuffer contents = new StringBuffer(); String line = null; while ((line = reader.readLine()) != null) { contents.append(line); contents.append("\n"); } return contents.toString(); } } catch (Exception ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } return null; } }
package com.yy.test;
import com.yy.common.SlackChannelEnum;
import com.yy.operation.SlackUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
/**
* @author :Max
* @date :Created in 2022/8/28 下午2:37
* @description:
*/
public class SlackTest {
static {
SlackUtil.setSlackConfig("https://hooks.slack.com/services/*******");
}
@Test
public void test(){
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel,"test ~");
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertTrue(true);
}
}
Copy after login
Sent successfully, you can see the information in the channelpackage com.yy.test; import com.yy.common.SlackChannelEnum; import com.yy.operation.SlackUtil; import org.junit.Assert; import org.junit.Test; import java.util.concurrent.TimeUnit; /** * @author :Max * @date :Created in 2022/8/28 下午2:37 * @description: */ public class SlackTest { static { SlackUtil.setSlackConfig("https://hooks.slack.com/services/*******"); } @Test public void test(){ SlackUtil.send(SlackChannelEnum.EXCEPTION.channel,"test ~"); try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Assert.assertTrue(true); } }
public class LoggerTest {
private static final Logger logger = Logger.getLogger(LoggerTest.class.getCanonicalName());
@Test
public void test() {
try {
int i = 1 / 0;
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
}
Copy after loginCopy after login
Rewrite the method of encapsulating log printingpublic class LoggerTest { private static final Logger logger = Logger.getLogger(LoggerTest.class.getCanonicalName()); @Test public void test() { try { int i = 1 / 0; } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } } }
package com.yy.operation;
import com.yy.common.SlackChannelEnum;
import org.apache.commons.lang.StringUtils;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* @author Max
* @date :Created in 2022/8/4 下午5:14
* @description:
*/
public class CommonLogger {
private Logger logger;
private CommonLogger(String className) {
logger = Logger.getLogger(className);
}
private static String SERVER;
private static String EXCEPTION_ALARM_FORMAT = "EXCEPTION 发生异常!\n环境 :{0}\n信息 :{1}\n详情 :{2}";
private static String WARNING_ALARM_FORMAT = "WARNING 发生告警!\n环境 :{0}\n信息 :{1}";
private static String SEVERE_ALARM_FORMAT = "SEVERE 发生告警!\n环境 :{0}\n信息 :{1}";
private static String LOG_ALARM_FORMAT = "LOG 发生告警!\n环境 :{0}\n信息 :{1}";
private static String USER_BEHAVIOR_FORMAT = "CUSTOMER \n环境 :{0}\n信息 :{1}";
static {
try{
InetAddress ip4 = Inet4Address.getLocalHost();
SERVER = ip4.getHostAddress();
}catch (Exception e){
SERVER ="undefined server";
}
}
public static CommonLogger getLogger(String name) {
return new CommonLogger(name);
}
/**
* Print exception information, send slack
*
* @param level
* @param msg
* @param e
*/
public void log(Level level, String msg, Throwable e) {
if(StringUtils.isBlank(msg)){
return;
}
msg =dolog(level,msg, e);
msg = MessageFormat.format(EXCEPTION_ALARM_FORMAT, SERVER, formatMsg(msg), getErrmessage(e));
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg);
}
/**
* Print user behavior information, send slack
*
* @param msg
*/
public void userBehaviorInfo(String msg) {
if(StringUtils.isBlank(msg)){
return;
}
msg =dolog(Level.INFO,msg);
msg = MessageFormat.format(USER_BEHAVIOR_FORMAT, SERVER, formatMsg(msg));
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg);
}
public String formatMsg(String msg){
StringBuilder source =new StringBuilder(logger.getName());
msg=transferMsgSource(source,msg);
return source.toString()+" "+msg;
}
/**
* Print warning severe information, send slack
*
* @param msg
*/
public void severe(String msg) {
if(StringUtils.isBlank(msg)){
return;
}
msg = dolog(Level.SEVERE,msg);
msg = MessageFormat.format(SEVERE_ALARM_FORMAT, SERVER, formatMsg(msg));
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg);
}
/**
* Print warning severe information, send slack
*
* @param msg
*/
public void warning(String msg) {
if(StringUtils.isBlank(msg)){
return;
}
msg = dolog(Level.WARNING,msg);
msg = MessageFormat.format(WARNING_ALARM_FORMAT, SERVER, formatMsg(msg));
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg);
}
/**
* Print warning log information, send slack
*
* @param msg
*/
public void log(Level severe, String msg) {
if(StringUtils.isBlank(msg)){
return;
}
msg =dolog(severe,msg);
msg = MessageFormat.format(LOG_ALARM_FORMAT, SERVER, formatMsg(msg));
SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg);
}
public static String getErrmessage(Throwable t) {
return getThrowable(t);
}
public void info(String msg) {
dolog(Level.INFO,msg);
}
public void fine(String msg) {
logger.fine(msg);
}
public void setLevel(Level level) {
logger.setLevel(level);
}
public String dolog(Level level, String msg) {
return dolog(level,msg,null);
}
/**
*
* @param level
* @param msg
* @param thrown
* @return msg="["+currentThread.getName()+"] "+a.getMethodName()+" "+msg;
*/
public String dolog(Level level, String msg, Throwable thrown) {
LogRecord lr = new LogRecord(level, msg);
lr.setLevel(level);
if(thrown!=null){
lr.setThrown(thrown);
}
Thread currentThread = Thread.currentThread();
StackTraceElement[] temp=currentThread.getStackTrace();
StackTraceElement a=(StackTraceElement)temp[3];
lr.setThreadID((int) currentThread.getId());
lr.setSourceClassName(logger.getName());
lr.setSourceMethodName(a.getMethodName());
lr.setLoggerName(logger.getName());
logger.log(lr);
return "["+currentThread.getName()+"] "+a.getMethodName()+" "+msg;
}
public static String getThrowable(Throwable e) {
String throwable = "";
if (e != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println();
e.printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
return throwable;
}
public static String transferMsgSource(StringBuilder source,String msg){
if(msg.indexOf(" ")>0){
String threadName = msg.substring(0,msg.indexOf(" "))+ " ";
msg=msg.substring(threadName.length());
source.insert(0,threadName);
if(msg.indexOf(" ")>0) {
String method = msg.substring(0, msg.indexOf(" "));
source.append( "." + method);
msg = msg.substring(method.length()+1);
}
}
return msg;
}
}
Copy after loginpackage com.yy.operation;
import java.text.MessageFormat;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerUtil {
private static Logger curLogger = Logger.getLogger(LoggerUtil.class.getCanonicalName());
private static ConcurrentHashMap<String, CommonLogger> loggers = new ConcurrentHashMap<String, CommonLogger>();
public static CommonLogger getLogger(Class<?> clazz) {
String className = clazz.getCanonicalName();
CommonLogger logger = loggers.get(className);
if (logger == null) {
logger = CommonLogger.getLogger(className);
curLogger.fine(MessageFormat.format("Register logger for {0}", className));
loggers.put(className, logger);
}
return logger;
}
}
Copy after login
Test log classIf the log class is changed when defining it, the code called does not need to be changed to minimize At the cost, the abnormal alarm function is integratedpackage com.yy.operation; import com.yy.common.SlackChannelEnum; import org.apache.commons.lang.StringUtils; import java.io.PrintWriter; import java.io.StringWriter; import java.net.Inet4Address; import java.net.InetAddress; import java.text.MessageFormat; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; /** * @author Max * @date :Created in 2022/8/4 下午5:14 * @description: */ public class CommonLogger { private Logger logger; private CommonLogger(String className) { logger = Logger.getLogger(className); } private static String SERVER; private static String EXCEPTION_ALARM_FORMAT = "EXCEPTION 发生异常!\n环境 :{0}\n信息 :{1}\n详情 :{2}"; private static String WARNING_ALARM_FORMAT = "WARNING 发生告警!\n环境 :{0}\n信息 :{1}"; private static String SEVERE_ALARM_FORMAT = "SEVERE 发生告警!\n环境 :{0}\n信息 :{1}"; private static String LOG_ALARM_FORMAT = "LOG 发生告警!\n环境 :{0}\n信息 :{1}"; private static String USER_BEHAVIOR_FORMAT = "CUSTOMER \n环境 :{0}\n信息 :{1}"; static { try{ InetAddress ip4 = Inet4Address.getLocalHost(); SERVER = ip4.getHostAddress(); }catch (Exception e){ SERVER ="undefined server"; } } public static CommonLogger getLogger(String name) { return new CommonLogger(name); } /** * Print exception information, send slack * * @param level * @param msg * @param e */ public void log(Level level, String msg, Throwable e) { if(StringUtils.isBlank(msg)){ return; } msg =dolog(level,msg, e); msg = MessageFormat.format(EXCEPTION_ALARM_FORMAT, SERVER, formatMsg(msg), getErrmessage(e)); SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg); } /** * Print user behavior information, send slack * * @param msg */ public void userBehaviorInfo(String msg) { if(StringUtils.isBlank(msg)){ return; } msg =dolog(Level.INFO,msg); msg = MessageFormat.format(USER_BEHAVIOR_FORMAT, SERVER, formatMsg(msg)); SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg); } public String formatMsg(String msg){ StringBuilder source =new StringBuilder(logger.getName()); msg=transferMsgSource(source,msg); return source.toString()+" "+msg; } /** * Print warning severe information, send slack * * @param msg */ public void severe(String msg) { if(StringUtils.isBlank(msg)){ return; } msg = dolog(Level.SEVERE,msg); msg = MessageFormat.format(SEVERE_ALARM_FORMAT, SERVER, formatMsg(msg)); SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg); } /** * Print warning severe information, send slack * * @param msg */ public void warning(String msg) { if(StringUtils.isBlank(msg)){ return; } msg = dolog(Level.WARNING,msg); msg = MessageFormat.format(WARNING_ALARM_FORMAT, SERVER, formatMsg(msg)); SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg); } /** * Print warning log information, send slack * * @param msg */ public void log(Level severe, String msg) { if(StringUtils.isBlank(msg)){ return; } msg =dolog(severe,msg); msg = MessageFormat.format(LOG_ALARM_FORMAT, SERVER, formatMsg(msg)); SlackUtil.send(SlackChannelEnum.EXCEPTION.channel, msg); } public static String getErrmessage(Throwable t) { return getThrowable(t); } public void info(String msg) { dolog(Level.INFO,msg); } public void fine(String msg) { logger.fine(msg); } public void setLevel(Level level) { logger.setLevel(level); } public String dolog(Level level, String msg) { return dolog(level,msg,null); } /** * * @param level * @param msg * @param thrown * @return msg="["+currentThread.getName()+"] "+a.getMethodName()+" "+msg; */ public String dolog(Level level, String msg, Throwable thrown) { LogRecord lr = new LogRecord(level, msg); lr.setLevel(level); if(thrown!=null){ lr.setThrown(thrown); } Thread currentThread = Thread.currentThread(); StackTraceElement[] temp=currentThread.getStackTrace(); StackTraceElement a=(StackTraceElement)temp[3]; lr.setThreadID((int) currentThread.getId()); lr.setSourceClassName(logger.getName()); lr.setSourceMethodName(a.getMethodName()); lr.setLoggerName(logger.getName()); logger.log(lr); return "["+currentThread.getName()+"] "+a.getMethodName()+" "+msg; } public static String getThrowable(Throwable e) { String throwable = ""; if (e != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println(); e.printStackTrace(pw); pw.close(); throwable = sw.toString(); } return throwable; } public static String transferMsgSource(StringBuilder source,String msg){ if(msg.indexOf(" ")>0){ String threadName = msg.substring(0,msg.indexOf(" "))+ " "; msg=msg.substring(threadName.length()); source.insert(0,threadName); if(msg.indexOf(" ")>0) { String method = msg.substring(0, msg.indexOf(" ")); source.append( "." + method); msg = msg.substring(method.length()+1); } } return msg; } }
package com.yy.operation; import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; public class LoggerUtil { private static Logger curLogger = Logger.getLogger(LoggerUtil.class.getCanonicalName()); private static ConcurrentHashMap<String, CommonLogger> loggers = new ConcurrentHashMap<String, CommonLogger>(); public static CommonLogger getLogger(Class<?> clazz) { String className = clazz.getCanonicalName(); CommonLogger logger = loggers.get(className); if (logger == null) { logger = CommonLogger.getLogger(className); curLogger.fine(MessageFormat.format("Register logger for {0}", className)); loggers.put(className, logger); } return logger; } }
public class LoggerTest { private static final Logger logger = Logger.getLogger(LoggerTest.class.getCanonicalName()); @Test public void test() { try { int i = 1 / 0; } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } } }
- You can not only print exception logs, but also print some key behaviors of users, such as recharging, etc. Multiple channels can be set up to send messages with different themes
- Thread pool can be optimized
- If developers cannot check slack in time, email can also be integrated. Mailclark application can be added to Slack (separate fee), after configuration Afterwards, the information in the launched channel can be automatically sent to any mailbox, and the recipient does not need to create a slack account. Please refer to the link for specific configuration.
package com.yy.common;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author :Max
* @date :Created in 2022/8/26 下午1:51
* @description:
*/
public class CommonThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String threadNamePrefix;
private final String nameSpecific;
private final boolean isDaemon;
public CommonThreadFactory(String nameSpecific) {
this(nameSpecifihttps://juejin.cn/post/7136858841756467230#heading-4c, false);
}
public CommonThreadFactory(String nameSpecific, boolean isDaemon) {
SecurityManager s = System.getSecurityManager();
this.group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
this.threadNamePrefix = "eg-pool-" + poolNumber.getAndIncrement() + "-thread";
this.nameSpecific = nameSpecific;
this.isDaemon = isDaemon;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, String.format("%s-%d-%s",
this.threadNamePrefix, threadNumber.getAndIncrement(), this.nameSpecific), 0);
t.setDaemon(isDaemon);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
Copy after loginpublic enum SlackChannelEnum {
EXCEPTION("#test-example");
public String channel;
SlackChannelEnum(String channel) {
this.channel = channel;
}
}
Copy after login
package com.yy.common; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * @author :Max * @date :Created in 2022/8/26 下午1:51 * @description: */ public class CommonThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String threadNamePrefix; private final String nameSpecific; private final boolean isDaemon; public CommonThreadFactory(String nameSpecific) { this(nameSpecifihttps://juejin.cn/post/7136858841756467230#heading-4c, false); } public CommonThreadFactory(String nameSpecific, boolean isDaemon) { SecurityManager s = System.getSecurityManager(); this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.threadNamePrefix = "eg-pool-" + poolNumber.getAndIncrement() + "-thread"; this.nameSpecific = nameSpecific; this.isDaemon = isDaemon; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, String.format("%s-%d-%s", this.threadNamePrefix, threadNumber.getAndIncrement(), this.nameSpecific), 0); t.setDaemon(isDaemon); t.setPriority(Thread.NORM_PRIORITY); return t; } }
public enum SlackChannelEnum { EXCEPTION("#test-example"); public String channel; SlackChannelEnum(String channel) { this.channel = channel; } }
The above is the detailed content of How to implement abnormal log alarm in JAVA based on Slack. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

In this article, we have kept the most asked Java Spring Interview Questions with their detailed answers. So that you can crack the interview.

Java 8 introduces the Stream API, providing a powerful and expressive way to process data collections. However, a common question when using Stream is: How to break or return from a forEach operation? Traditional loops allow for early interruption or return, but Stream's forEach method does not directly support this method. This article will explain the reasons and explore alternative methods for implementing premature termination in Stream processing systems. Further reading: Java Stream API improvements Understand Stream forEach The forEach method is a terminal operation that performs one operation on each element in the Stream. Its design intention is

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

Guide to TimeStamp to Date in Java. Here we also discuss the introduction and how to convert timestamp to date in java along with examples.

Capsules are three-dimensional geometric figures, composed of a cylinder and a hemisphere at both ends. The volume of the capsule can be calculated by adding the volume of the cylinder and the volume of the hemisphere at both ends. This tutorial will discuss how to calculate the volume of a given capsule in Java using different methods. Capsule volume formula The formula for capsule volume is as follows: Capsule volume = Cylindrical volume Volume Two hemisphere volume in, r: The radius of the hemisphere. h: The height of the cylinder (excluding the hemisphere). Example 1 enter Radius = 5 units Height = 10 units Output Volume = 1570.8 cubic units explain Calculate volume using formula: Volume = π × r2 × h (4

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHP is suitable for web development, with simple syntax and high execution efficiency. 2. Python is suitable for data science and machine learning, with concise syntax and rich libraries.

Java is a popular programming language that can be learned by both beginners and experienced developers. This tutorial starts with basic concepts and progresses through advanced topics. After installing the Java Development Kit, you can practice programming by creating a simple "Hello, World!" program. After you understand the code, use the command prompt to compile and run the program, and "Hello, World!" will be output on the console. Learning Java starts your programming journey, and as your mastery deepens, you can create more complex applications.

Spring Boot simplifies the creation of robust, scalable, and production-ready Java applications, revolutionizing Java development. Its "convention over configuration" approach, inherent to the Spring ecosystem, minimizes manual setup, allo
