>  기사  >  Java  >  Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

王林
王林앞으로
2023-05-01 18:04:071421검색

    1. 기능 소개

    구현 논리: 일반적인 상황에서 코드는 예외가 발생한 예외를 처리합니다. 이 기사에서는 로그를 인쇄할 때, 또한 비정상적인 정보는 Slack 채널로 전송됩니다. 개발 또는 운영 및 유지 관리 담당자는 Slack 계정을 생성하고 채널에 가입하여 실시간으로 비정상적인 정보에 대한 알림을 받을 수 있습니다.

    2. Slack 소개

    Slack 데스크톱/노트북 컴퓨터, 모바일 기기에서 단일 애플리케이션으로, 웹 애플리케이션으로 사용할 수 있는 웹 기반 실시간 커뮤니케이션 도구입니다. 기본적으로 이곳은 개인 채팅 및 협업 공간입니다. 많은 회사에서 이메일/비공개 포럼/채팅룸을 기본 내부 텍스트 기반 커뮤니케이션 채널로 대체했습니다.

    채팅 그룹 + 대규모 도구 통합 + 파일 통합 + 통합 검색으로 이해될 수 있습니다. 2014년 말 현재 Slack은 이메일, 문자 메시지, Google 드라이브, Twitter, Trello, Asana, GitHub 등 65개의 도구와 서비스를 통합하여 다양한 단편화된 기업 커뮤니케이션과 협업을 통합할 수 있습니다. 몇 가지 중요한 개념:

    Workspace: 꽤 작업 공간이므로 사용자는 다양한 작업 공간에 참여하거나 만들 수 있습니다. 작업 공간의 이름과 URL은 회사 이름이 됩니다.

    Channel: 채널은 서로 다른 팀이나 주제로 나눌 수 있으며, 채널 내 구성원이 채널에서 정보를 공유하는 WeChat과 동일하게 이해될 수도 있습니다.

    3. 사전 준비

    slack 구성

    • 계정을 만들고 로그인하세요. 앱을 사용하거나 브라우저로 웹 버전에 로그인할 수 있습니다.

    • 나만의 워크스페이스를 만들고, 초대도 가능합니다. 다른 사람들이 작업 공간에 참여하도록 합니다.

    • 채널을 만들고 동료를 초대하여 채널에 메시지를 보낼 수 있으며, 채널에 참여하는 모든 사람이 메시지를 볼 수 있습니다.

    작업 공간에 애플리케이션 추가 Incoming WebHook을 선택하세요. 채널을 등록하고 Webhook URL을 저장한 후 팔로우하세요. 프로그램은 Webhook을 통해 구현되어 채널에 메시지를 보냅니다.

    Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    pom.

    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>

    SlackUtil test

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

    성공적으로 전송되면 채널에서 정보를 볼 수 있습니다.
    2 . 인쇄 로그 클래스 재작성

    공통 예외 로깅 처리

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

    인쇄 로그 캡슐화 방법 재작성Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    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;
        }
    }
    테스트 결과, 비정상적인 정보가 채널에 인쇄되어 개발 및 운영 담당자가 쉽게 찾을 수 있습니다

    5. 최적화 및 확장 아이디어

    인쇄만 가능하지 않습니다 예외 로그를 ​​인쇄할 뿐만 아니라 재충전 등과 같은 사용자의 일부 주요 동작도 인쇄합니다. 여러 채널을 설정하여 다양한 테마의 메시지를 보낼 수 있습니다. Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법

    예 스레드 풀을 최적화하세요
    • 개발자가 시간 내에 Slack을 확인할 수 없는 경우 , 이메일을 통합할 수도 있습니다. 메일클락(mailclark) 애플리케이션을 Slack에 추가할 수 있습니다(별도 요금). 구성 후 채널의 정보를 활성화할 수 있으며 수신자는 Slack 계정을 만들 필요가 없습니다. . 구체적인 구성은 링크를 참고해주세요.
    • 기타 코드
    • 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);
              }
          }
      }

    위 내용은 Slack을 기반으로 JAVA에서 이상 로그 알람을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제