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>
4. Specific implementation1. Implement Slack to send messagesSlackUtil Send message to Slack tool classpackage 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);
}
}
}
}
Initiate a request to webhook through Urlencodepackage 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;
}
}
SlackUtil testpackage 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);
}
}
Sent successfully, you can see the information in the channel
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);
}
}
}
Rewrite the method of encapsulating log printingpackage 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;
}
}
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 integratedpublic 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); } } }Test results, abnormal information printed in the channel, convenient for development and operation personnel to locate
- 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;
}
}
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!

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.

The article discusses creating and using custom Java libraries (JAR files) with proper versioning and dependency management, using tools like Maven and Gradle.

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

The article discusses using JPA for object-relational mapping with advanced features like caching and lazy loading. It covers setup, entity mapping, and best practices for optimizing performance while highlighting potential pitfalls.[159 characters]

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa


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

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Chinese version
Chinese version, very easy to use

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Dreamweaver Mac version
Visual web development tools

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.