Maison  >  Article  >  Java  >  Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

王林
王林avant
2023-05-01 18:04:071466parcourir

    1. Introduction à la fonction

    Logique d'implémentation : dans des circonstances normales, le code gérera les endroits où des exceptions se produiront. La plus basique est d'imprimer le journal. , des informations anormales seront également envoyées au canal Slack. Le personnel de développement ou d'exploitation et de maintenance peut créer un compte Slack et rejoindre le canal pour recevoir des alertes d'informations anormales en temps réel.

    2. Introduction à Slack

    Slack Il s'agit d'un outil de communication Web en temps réel qui peut être utilisé comme une application unique sur les ordinateurs de bureau/portables, les appareils mobiles et comme application Web. Fondamentalement, c'est votre salle de discussion et de collaboration privée. Pour de nombreuses entreprises, il a remplacé les e-mails, les forums privés et les salons de discussion comme principal canal de communication interne basé sur le texte.

    peut être compris comme un groupe de discussion + une intégration d'outils à grande échelle + une intégration de fichiers + une recherche unifiée. Fin 2014, Slack avait intégré 65 outils et services tels que la messagerie électronique, les messages texte, Google Drives, Twitter, Trello, Asana, GitHub, etc., qui peuvent rassembler diverses communications et collaborations d'entreprise fragmentées. Plusieurs concepts importants :

    Workspace : Tout un espace de travail, les utilisateurs peuvent rejoindre ou créer différents espaces de travail, plusieurs fois, le nom et l'URL de l'espace de travail seront le nom de l'entreprise.

    Channel : les chaînes peuvent être divisées en différentes équipes ou sujets, et peuvent également être considérées comme équivalentes à WeChat, où les membres de la chaîne partagent des informations dans la chaîne.

    3. Préparation préliminaire

    configuration Slack

    • Créez un compte et connectez-vous. Vous pouvez utiliser l'application ou vous connecter à la version Web avec un navigateur

    • Créez votre propre espace de travail, et vous pouvez également inviter d'autres à rejoindre l'espace de travail.

    • Créez une chaîne et invitez des collègues à la rejoindre. À ce stade, vous pouvez envoyer des messages à la chaîne, et tous ceux qui rejoignent la chaîne peuvent voir le message

    Ajouter l'application WebHook entrant à l'espace de travail, sélectionnez la chaîne, enregistrez l'URL du Webhook et suivez Le programme sera implémenté via Webhook pour envoyer des messages à la chaîne.

    Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    pom

    Initiez une demande au webhook via Urlencode

    <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>

    Test SlackUtil

    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);
                }
            }
        }
    }

    Envoyé avec succès, vous pouvez voir les informations dans le canal.
    2 .Réécrivez la classe du journal d'impression

    Traitement commun de la journalisation des exceptions

    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;
        }
    }

    Réécrivez la méthode d'encapsulation du journal d'impressionComment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    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);
            }
        }
    }

    Classe du journal de test

    Lorsque la classe de journal est définie et que des modifications se produisent, le code d'appel n'a pas besoin d'être modifié. . La fonction d'alarme d'exception est intégrée à moindre coût
    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;
        }
    }
    Résultats des tests, informations anormales imprimées dans le canal, faciles à localiser pour le personnel de développement et d'exploitation

    5. Les idées d'optimisation et d'expansion

    ne peuvent pas seulement. imprimer les journaux d'exceptions, mais aussi imprimer certains comportements clés des utilisateurs, tels que la recharge, etc. Plusieurs canaux peuvent être configurés pour envoyer des messages avec des thèmes différents Comment implémenter une alarme de journal anormale dans JAVA basé sur Slack

    Oui Optimiser le pool de threads
    • Si les développeurs ne peuvent pas enregistrer Slack dans temps, ils peuvent également intégrer le courrier électronique. L'application mailclark peut être ajoutée à Slack (frais séparés). Après la configuration, les informations du canal peuvent être activées et les e-mails peuvent être automatiquement envoyés à n'importe quelle boîte aux lettres. compte. Veuillez vous référer au lien pour une configuration spécifique.
    • Autres codes
    • 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);
              }
          }
      }

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer