Logik pelaksanaan: Dalam keadaan biasa, pengecualian akan diproses dalam kod , perkara yang paling asas adalah untuk mencetak log Artikel ini akan menyedari bahawa apabila mencetak log, maklumat pengecualian akan dihantar ke saluran Slack pada masa yang sama Kakitangan pembangunan atau operasi dan penyelenggaraan boleh membuat akaun Slack dan menyertai saluran untuk menerima makluman maklumat yang tidak normal masa sebenar.
Slack ialah alat komunikasi masa nyata berasaskan web yang boleh digunakan sebagai satu aplikasi pada komputer desktop/laptop, peranti mudah alih dan sebagai aplikasi web . Pada asasnya, ini ialah bilik sembang dan kerjasama peribadi anda. Bagi kebanyakan syarikat, ia telah menggantikan e-mel/forum peribadi/bilik sembang sebagai saluran komunikasi berasaskan teks dalaman utama.
Ia boleh difahami sebagai kumpulan sembang + penyepaduan alat berskala besar + penyepaduan fail + carian bersatu . Sehingga penghujung 2014, Slack telah menyepadukan 65 alat dan perkhidmatan seperti e-mel, mesej teks, Google Drive, Twitter, Trello, Asana, GitHub, dll., yang boleh menghimpunkan pelbagai komunikasi dan kerjasama perusahaan yang berpecah-belah. Beberapa konsep penting:
Ruang kerja: Cukup ruang kerja Pengguna boleh menyertai atau mencipta ruang kerja yang berbeza Banyak kali, nama dan URL ruang kerja akan menjadi nama syarikat.
Saluran: Saluran boleh dibahagikan kepada pasukan atau topik yang berbeza, dan juga boleh difahami sebagai setara dengan WeChat, di mana ahli dalam saluran berkongsi maklumat dalam saluran.
Buat akaun dan log masuk. Anda boleh menggunakan apl atau log masuk ke versi web dengan pelayar
Buat ruang kerja anda sendiri dan jemput orang lain untuk menyertainya.
Buat saluran dan jemput rakan sekerja untuk menyertai pada masa ini, anda boleh menghantar mesej ke saluran dan semua orang yang menyertai saluran itu boleh melihat mesej itu
WebHook Masuk ke kawasan, pilih saluran dan simpan URL Webhook Kemudian, anda akan menggunakan program pelaksanaan Webhook untuk menghantar mesej ke saluran.
pom.xml<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); } } } }
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; } }
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); } }
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); } } }
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; } }
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); } } }Keputusan ujian, maklumat abnormal tercetak muncul dalam saluran, yang mudah untuk kakitangan pembangunan dan operasi untuk mengesan 5. Idea Pengoptimuman dan pengembangan
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; } }
Atas ialah kandungan terperinci Bagaimana untuk melaksanakan penggera log tidak normal dalam JAVA berdasarkan Slack. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!