范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

JAVA基于Slack实现异常日志报警

  一、功能介绍
  在我们日常开发中,如果系统在线上环境上,发生异常,开发人员不能及时知晓来修复,可能会造成重大的损失,因此后端服务中加入异常报警的功能是十分必要的,而开发一个功能全面的异常报警服务,可能会花费较长的周期,今天给大家带来一种基于Slack实现异常日志报警的办法。
  实现逻辑:一般情况下,代码中都会对会出现异常的地方,进行处理,最基本的就是打印日志,本文将实现在打印日志时,同时将异常信息发送到Slack频道中,开发或运维人员创建Slack账号,加入频道,便可实时收到异常信息的告警。二、Slack介绍
  Slack 它是一种基于Web的实时通信工具,可作为台式机/笔记本电脑、移动设备的单个应用程序以及Web应用程序使用。基本上,它是您的私人聊天和协作室。对于许多公司而言,它已取代电子邮件/私人论坛/聊天室成为主要的内部基于文本的沟通渠道。可以理解为它是聊天群组 + 大规模工具集成 + 文件整合 + 统一搜索。截至2014年底,Slack 已经整合了电子邮件、短信、Google Drives、Twitter、Trello、Asana、GitHub 等 65 种工具和服务,可以把各种碎片化的企业沟通和协作集中到一起。几个重要的概念:
  工作区:相当去工作空间,用户可以加入或者创建不同的工作区,很多时候,工作区的名称和URL将是公司名称。
  频道:频道可以区分为不同的团队或者主题,也可以理解成相当于微信,频道中的成员共享频道中的信息。三、前期准备slack配置创建账号,登录,可以使用app或者用浏览器登录网页版创建自己的工作区,还可以邀请其他人加入工作区。创建频道,邀请同事加入,此时可以往频道中发信息,加入频道的人都可以看到信息工作区添加应用Incoming WebHook,选择频道,保存Webhook URL,后面将通过Webhook实现程序往频道中发消息。pom.xml              org.apache.httpcomponents         httpclient         4.5.2                   com.alibaba         fastjson         1.2.83                   commons-configuration         commons-configuration         1.10                   junit         junit         4.10         test      四、具体实现1.实现Slack发送消息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(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+" msg:"+msg);             }         }     }   }向 webhook发起请求通过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(" ");                 }                 return contents.toString();             }         } catch (Exception ex) {             logger.log(Level.SEVERE, ex.getMessage(), ex);         }         return null;     }  }SlackUtil测试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);     } }2.重写打印日志类常见异常打日志处理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 发生异常! 环境 :{0} 信息 :{1} 详情 :{2}";      private static String WARNING_ALARM_FORMAT = "WARNING 发生告警! 环境 :{0} 信息 :{1}";      private static String SEVERE_ALARM_FORMAT = "SEVERE 发生告警! 环境 :{0} 信息 :{1}";      private static String LOG_ALARM_FORMAT = "LOG 发生告警! 环境 :{0} 信息 :{1}";      private static String USER_BEHAVIOR_FORMAT = "CUSTOMER  环境 :{0} 信息 :{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 loggers = new ConcurrentHashMap();        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);         }     } }优化扩展想法可以不仅仅实现打印异常日志,也可以打印用户的一些关键行为,如充值等,频道可以设置多个,发送不同主题的消息可以优化线程池如果开发人员不能及时查看slack,也可以集成电子邮件,Slack中可以添加mailclark应用(单独收费),经过配置后,发动频道中的信息,可以自动邮件发送给任意邮箱,接受者无需创建slack账号。

恭喜!邓亚萍16岁儿子再夺2冠!技术精湛打法凶狠,身高成硬伤没有实现梦想的运动员,希望自己孩子能够帮助完成梦想,而成功的运动员则同样希望孩子继承自己的衣钵,将毕生经验倾囊相授,看着孩子在自己曾经辉煌的项目上,再次成功,也会让自己很有成就感,同曦官方球队正式与外籍球员QJ皮特森完成签约直播吧9月16日讯南京同曦篮球俱乐部官方宣布,球队与外籍球员QJ皮特森完成签约,新赛季他将身披7号球衣。球队公告原文如下南京同曦篮球俱乐部正式与外籍球员QJ皮特森完成签约,待向CB37个项目!北京与廊坊北三县签下280亿元大单北京日报客户端记者曹政北京在产业基础设施公共服务等领域的优质项目已经连续4年落地河北廊坊北三县。在9月15日举行的2022年北京通州河北廊坊北三县项目推介洽谈会上,签约合作项目共3新大陆工业时代向数字时代演变一切皆有可能证券时报记者唐维在数字中国建设的国家战略中,新大陆一直是矢志不渝的创新者。近日,新大陆(000997)董事长王晶在接受证券时报记者专访时表示。数字两字,已成为近几年来王晶最闪亮甚至净亏损20亿,B站奔向商业化作者刘雨婷编辑陈彦旭运营陈小妍另镜(IDDMS012)B站的价值来自于用户,而在变现之路上,B站仍面临难题。今年二季度,B站月活用户数首次突破3亿,同比增长29,离B站2023年4再抠门的大厂,也不敢省这笔钱深燃(shenrancaijing)原创作者金玙璠编辑魏佳环境不好,没人能挡住互联网大厂降本增效,但在一件事上例外,各家反而比着花钱。这就是ESG(环境社会和公司治理)报告,人称企影像旗舰5000万像素60倍变焦2K屏,vivo高端旗舰真的很保值大家在买手机的时候,是否会和买车一样,在意一下手机的保值率呢。目前国内的手机市场发展虽然趋于平缓,但还是很有活力的,各家手机厂商还是保持着自己更新手机的速度,力求在每年都做到创新,顺丰寄丢20克黄金,保价八千只赔两千,网友顺丰改名叫顺走?顺丰回应9月10日,杭州萧山的小刘在顺丰下单了一个同城急送的业务,把20克黄金送到住在拱墅区的一位客户住处。20克黄金,目前市场价值约8000元,小刘特意进行了保价,保价金额8000元。不WMO警告未来几十年热浪将频繁出现,救援机器人应用前景广阔8月11日,小米集团创始人董事长雷军发布了全尺寸人形机器人CyberOne。据雷军介绍,人形机器人是打造一个连接人与万物科技生态的探索过程,也是未来智能机器人的重点发展方向,因其人新型智能交通行驶工具不亚于一场工业革命新型智能交通工具技术简介现在的智能驾驶技术没有打开思路,当然离实现全面智能交通还有很远的路。不打破传统思维,现在的全智能驾驶技术也改变不了城市交通越来越拥堵的趋势,更改变不了山区交创业老故事。连续篇。第6集贾跃亭小白脸富豪失信造假之路提起贾跃亭,知道他的更多是乐视网他是富豪,欠债逃到美国。不知道是他创业靠当小白脸,乐视在中国上市靠财务造假,法拉第未来FF在美国上市靠忽悠。高考贾跃亭第2次高考,考了一个大专,毕业
人为什么会长老人斑?红霉素软膏可以去除老人斑吗?看后明白了相信每个家庭都有一个专业的小药箱,将摆放着各种各样的药物,有退烧药,烫伤药,解热药,消炎药,镇痛药,随着医疗水平的发展,越来越多的疑难杂症,也都得到有效根治,在网络科技高速发展的今1290g的我和1370g的弟弟285周双胎1290g1370g,这不仅仅是一组数字,更是两个珍贵的小生命和一个家庭的希望。2022年5月18日,我和弟弟在山东省中医院产科顺利降生了。我们在妈妈肚子里只待了285回顾广西女子着装清凉摆夜摊,穿衣风格引热议,很多男子边喝边看夏日热浪来袭,气温的升高连带着很多人的心也开始火热了起来。要知道每到夏天到来,很多年轻靓丽的女生就会穿着清凉打扮出现在街头,不过也是因此一些人会对女性的穿着打扮指指点点。在广西夜市破事精英开播职场版爱情公寓,但国产情景喜剧还能期待吗?在国产电视剧领域,情景喜剧是非常特殊的剧种。这种剧集类型,和时下流行的脱口秀素描喜剧等形式一样,都是舶来品。上世纪九十年代,著名导演英达率先将这一形式引入中国,推出了我爱我家一炮而ampampquot水上怪物ampampquot再次现身,俄罗斯复活威慑美国杀手锏在冷战时期曾经震惊了西方世界的里海怪物,很可能很快就要复活了。当年美国人第一次看到这种怪物时,几乎完全不敢相信。这种武器的外形很像是飞机,但它却能够在水中高速行驶。当时各国根本不知进球网切尔西希望今夏签斯特林,同时让卢卡库离开直播吧6月20日讯据进球网报道,切尔西的目标是在今夏的转会窗口签下斯特林,同时他们关于卢卡库离开的谈判仍在继续进行当中。国际米兰已经向蓝军开出600万英镑的租借费用报价,不过切尔西张雨霏摘铜笑容灿烂!中国组合世锦赛创造历史,美国名将成功卫冕2022年6月20日,游泳世锦赛继续在匈牙利布达佩斯进行,第二个比赛日结束,中国队获得1金1铜,花样游泳双人技术自选决赛,中国组合王芊懿王柳懿夺得金牌,创造新的历史,这是中国队在本世锦赛花游双人技术自选决赛上演双胞胎大战中国组合王芊懿王柳懿问鼎金牌中国体育讯北京时间6月19日晚,在匈牙利布达佩斯举行的第19届世界游泳锦标赛决出花样游泳双人技术自选金牌,25岁的中国双胞胎姐妹王柳懿王芊懿战胜一众对手,以总分93。7536分问鼎万众期待香港特区新班子,祝贺孙东任香港创新科技及工业局局长根据香港特别行政区第六任行政长官李家超的提名,国务院2022年6月19日任命了香港特别行政区第六届政府主要官员。在一国两制踏入新阶段,香港进入由治而兴新篇章的重要时刻,新一届特区管拜登访问中东前夕,德黑兰打出一套组合拳,压力来到美国这边日前美国劳工部公布数据,5月份美国消费者价格指数CPI同比增长8。6,创下1984年以来的最大涨幅,而且种种迹象表明,美国通胀问题还将进一步加剧,如何解决已经成为拜登政府当前最主要今夏流行一种裙叫三宅麻花褶裙!时髦显瘦,5060岁穿更美有一句话叫,高处见心态,低处见人品。真正有修养的女人,从来不会因为身份的贵贱处境的好坏地位的高低而改变自己的行为和准则。菜根谭有云人品极处,本心使然。身处微尘,心中有光,装得下日月