ホームページ  >  記事  >  Java  >  SlackをベースにJAVAで異常ログアラームを実装する方法

SlackをベースにJAVAで異常ログアラームを実装する方法

王林
王林転載
2023-05-01 18:04:071421ブラウズ
    #1. 関数の紹介

    実装ロジック: 通常の状況では、例外はコード内で処理されます。これは最も基本的なことです。この記事では、ログを印刷する際に、同時に例外情報が Slack チャネルに送信されることを理解します。開発担当者や運用保守担当者は、Slack アカウントを作成してチャネルに参加すると、異常情報のアラートを受け取ることができます。リアルタイム。

    2. Slack の概要

    Slack は、デスクトップ/ラップトップ コンピューター、モバイル デバイス上で単一のアプリケーションとして、また Web アプリケーションとして使用できる、Web ベースのリアルタイム コミュニケーション ツールです。 。基本的に、これはプライベートなチャットおよびコラボレーション ルームです。多くの企業にとって、電子メール/プライベート フォーラム/チャット ルームに代わって、主要な社内テキストベースのコミュニケーション チャネルとなっています。

    チャットグループ、大規模ツール統合、ファイル統合、統合検索であることが分かります。 2014 年末の時点で、Slack には電子メール、テキスト メッセージ、Google ドライブ、Twitter、Trello、Asana、GitHub など 65 のツールとサービスが統合されており、断片化された企業のさまざまなコミュニケーションやコラボレーションを 1 つにまとめることができます。いくつかの重要な概念:

    ワークスペース: 非常に優れたワークスペースです。ユーザーはさまざまなワークスペースに参加したり作成したりできます。多くの場合、ワークスペースの名前と URL は会社名になります。

    チャネル: チャネルはさまざまなチームまたはトピックに分けることができ、チャネル内のメンバーがチャネル内の情報を共有する WeChat と同等のものとして理解することもできます。

    3. 事前準備

    slack設定

    • アカウントを作成してログインします。アプリを使用するか、Web版にログインします。ブラウザ

    • 独自のワークスペースを作成し、他の人をワークスペースに招待します。

    • #チャンネルを作成し、同僚を参加に招待します。この時点で、チャンネルにメッセージを送信でき、チャンネルに参加している全員がそのメッセージを見ることができます
    • Work アプリケーション
    Incoming WebHook

    をエリアに追加し、チャネルを選択して Webhook URL を保存します。後で Webhook 実装プログラムを使用してチャネルにメッセージを送信します。

    SlackをベースにJAVAで異常ログアラームを実装する方法

    SlackをベースにJAVAで異常ログアラームを実装する方法

    SlackをベースにJAVAで異常ログアラームを実装する方法

    #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>
    SlackをベースにJAVAで異常ログアラームを実装する方法 4. 具体的な実装

    1. メッセージを送信するために Slack を実装します

    SlackUtil 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<Runnable>(200),new CommonThreadFactory("Slack"), new ThreadPoolExecutor.DiscardPolicy());
        private static String MSG_FORMAT ="payload=&#39;{&#39;"channel": "{0}", "username": "{1}", "text": "{2}", "icon_emoji": ":ghost:"&#39;}&#39;" ;
        /**
         * 保存的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(""","&#39;").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);
                }
            }
        }
    }

    Urlencode を通じて Webhook へのリクエストを開始します

    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;
        }
    }
    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. 印刷ログ クラスを書き換えます

    SlackをベースにJAVAで異常ログアラームを実装する方法Common例外 ロギング処理

    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);
            }
        }
    }
    テスト結果、異常情報がチャネルに出力され、開発および運用担当者が見つけやすくなります

    #5. 最適化と拡張のアイデア

    SlackをベースにJAVAで異常ログアラームを実装する方法

    例外ログを出力するだけでなく、充電などのユーザーの重要な行動も出力できます。さまざまなテーマのメッセージを送信できます

    • スレッド プールを最適化できます

    • #開発者が時間内に余裕を確認できない場合は、電子メールを統合することもできます。 Mailclark アプリケーションは設定後に Slack に追加できます (別途料金)。その後、起動したチャネル内の情報は任意のメールボックスに自動的に送信され、受信者は Slack アカウントを作成する必要はありません。具体的な構成についてはリンクを参照してください。
    • その他のコード
    • 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;
          }
      }

    以上がSlackをベースにJAVAで異常ログアラームを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。