SlackをベースにJAVAで異常ログアラームを実装する方法
チャットグループ、大規模ツール統合、ファイル統合、統合検索であることが分かります。 2014 年末の時点で、Slack には電子メール、テキスト メッセージ、Google ドライブ、Twitter、Trello、Asana、GitHub など 65 のツールとサービスが統合されており、断片化された企業のさまざまなコミュニケーションやコラボレーションを 1 つにまとめることができます。いくつかの重要な概念:
ワークスペース: 非常に優れたワークスペースです。ユーザーはさまざまなワークスペースに参加したり作成したりできます。多くの場合、ワークスペースの名前と URL は会社名になります。
チャネル: チャネルはさまざまなチームまたはトピックに分けることができ、チャネル内のメンバーがチャネル内の情報を共有する WeChat と同等のものとして理解することもできます。
3. 事前準備slack設定- アカウントを作成してログインします。アプリを使用するか、Web版にログインします。ブラウザ
- 独自のワークスペースを作成し、他の人をワークスペースに招待します。 #チャンネルを作成し、同僚を参加に招待します。この時点で、チャンネルにメッセージを送信でき、チャンネルに参加している全員がそのメッセージを見ることができます
- Work アプリケーション
をエリアに追加し、チャネルを選択して Webhook URL を保存します。後で Webhook 実装プログラムを使用してチャネルにメッセージを送信します。
<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>

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='{'"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); } } } }
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. 印刷ログ クラスを書き換えます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. 最適化と拡張のアイデア
- スレッド プールを最適化できます #開発者が時間内に余裕を確認できない場合は、電子メールを統合することもできます。 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 サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4
