You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
13 KiB
319 lines
13 KiB
package com.fr.design.carton; |
|
|
|
|
|
import com.fr.design.i18n.Toolkit; |
|
import com.fr.general.GeneralUtils; |
|
import com.fr.json.JSON; |
|
import com.fr.json.JSONArray; |
|
import com.fr.json.JSONObject; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.stable.StableUtils; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.xml.XMLPrintWriter; |
|
import com.fr.stable.xml.XMLReadable; |
|
import com.fr.stable.xml.XMLWriter; |
|
import com.fr.stable.xml.XMLableReader; |
|
import sun.awt.AppContext; |
|
|
|
import javax.swing.SwingWorker; |
|
import java.io.IOException; |
|
import java.io.File; |
|
import java.io.BufferedReader; |
|
import java.io.FileReader; |
|
import java.text.SimpleDateFormat; |
|
import java.util.List; |
|
import java.util.ArrayList; |
|
import java.util.HashMap; |
|
import java.util.Map; |
|
import java.util.Date; |
|
import java.util.Calendar; |
|
|
|
import static com.fr.design.carton.CartonConstants.DEBUG_MAIN_CLASS_NAME; |
|
import static com.fr.design.carton.CartonConstants.EASY_CHECKER_FILE_NAME; |
|
import static com.fr.design.carton.CartonConstants.JOURNAL_FILE_PATH; |
|
import static com.fr.design.carton.CartonConstants.TIMER_CHECKER_FILE_NAME; |
|
|
|
public class SwitchForSwingChecker implements XMLReadable, XMLWriter { |
|
|
|
/** |
|
* XML标签 |
|
*/ |
|
public static final String XML_TAG = "SwitchForSwingChecker"; |
|
/** |
|
* 定时任务的开关 |
|
*/ |
|
private static boolean checkerTimerSwitch = false; |
|
/** |
|
* 简单记录事件执行时间的开关 |
|
*/ |
|
private static boolean easyChecker = false; |
|
/** |
|
* UI性能监控埋点的开关 |
|
*/ |
|
private static boolean latencyMonitor = true; |
|
/** |
|
* 一个标识位用于区分耗时任务时长检测(简单检测)和timer检测 |
|
*/ |
|
public static final int TIMER_CHECK_FLAG = 0; |
|
public static final int EASY_CHECK_FLAG = 1; |
|
|
|
public static boolean isCheckerTimerSwitch() { |
|
return checkerTimerSwitch; |
|
} |
|
|
|
public static boolean isEasyChecker() { |
|
return easyChecker; |
|
} |
|
|
|
/** |
|
* 是否开启UI性能检测 |
|
*/ |
|
public static boolean isLatencyMonitoring() { |
|
return latencyMonitor; |
|
} |
|
|
|
public static volatile SwitchForSwingChecker switchForSwingChecker = new SwitchForSwingChecker(); |
|
|
|
public static SwitchForSwingChecker getInstance() { |
|
return switchForSwingChecker; |
|
} |
|
|
|
public static void startTimerChecker() { |
|
if (!checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.initTimer(); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer(); |
|
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true); |
|
checkerTimerSwitch = true; |
|
if (!easyChecker) { |
|
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); |
|
} |
|
} |
|
} |
|
|
|
public static void stopTimerChecker() { |
|
if (checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.stopTimer(); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().stopTimer(); |
|
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(false); |
|
checkerTimerSwitch = false; |
|
if (!easyChecker) { |
|
EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow(); |
|
} |
|
} |
|
} |
|
|
|
public static void startEasyChecker() { |
|
if (!easyChecker) { |
|
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true); |
|
easyChecker = true; |
|
if (!checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); |
|
} |
|
} |
|
} |
|
|
|
public static void stopEasyChecker() { |
|
if (easyChecker) { |
|
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(false); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(false); |
|
easyChecker = false; |
|
if (!checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow(); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* 获取文件名字以及判断文件是否存在 |
|
*/ |
|
private static CartonFiles getFiles(String date) { |
|
String[] split = date.split("-"); |
|
int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]); |
|
String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date); |
|
File file1 = new File(StableUtils.pathJoin(dirPath, EASY_CHECKER_FILE_NAME)); |
|
File file2 = new File(StableUtils.pathJoin(dirPath, TIMER_CHECKER_FILE_NAME)); |
|
File[] files = new File[2]; |
|
files[0] = file1; |
|
files[1] = file2; |
|
CartonFiles cartonFiles = new CartonFiles(); |
|
cartonFiles.setEasyCheckerFile(file1); |
|
cartonFiles.setTimerCheckerFile(file2); |
|
return cartonFiles; |
|
} |
|
|
|
/** |
|
* 处理文件 |
|
* 一共四种情况, |
|
* 两个文件都不存在 |
|
* 文件一存在,文件二不存在 |
|
* 文件二存在,文件一不存在 |
|
* 两个文件都存在 |
|
*/ |
|
private static List<CartonUploadMessage> getCartonLog(File easyFile, File timerFile) { |
|
List<CartonUploadMessage> res = new ArrayList<>(); |
|
List<CartonUploadMessage> easyFileCartonLog = getEasyFileCartonLog(easyFile); |
|
List<CartonUploadMessage> timerFileCartonLog = getTimerFileCartonLog(timerFile); |
|
Map<String, CartonUploadMessage> easyFileMap = new HashMap<>(); |
|
for (CartonUploadMessage cartonUploadMessage : easyFileCartonLog) { |
|
easyFileMap.put(cartonUploadMessage.getHangCount(), cartonUploadMessage); |
|
res.add(cartonUploadMessage); |
|
} |
|
for (CartonUploadMessage cartonUploadMessage : timerFileCartonLog) { |
|
String hangCount = cartonUploadMessage.getHangCount(); |
|
if (easyFileMap.containsKey(hangCount)) { |
|
cartonUploadMessage.setThreadTime(easyFileMap.get(hangCount).getThreadTime()); |
|
} |
|
res.add(cartonUploadMessage); |
|
} |
|
return res; |
|
} |
|
|
|
private static List<CartonUploadMessage> getTimerFileCartonLog(File file) { |
|
List<CartonUploadMessage> res = new ArrayList<>(); |
|
try { |
|
StringBuilder stringBuilder = new StringBuilder(); |
|
stringBuilder.append("["); |
|
BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); |
|
String line1; |
|
while ((line1 = bufferedReader1.readLine()) != null) { |
|
stringBuilder.append(line1); |
|
} |
|
bufferedReader1.close(); |
|
stringBuilder.append("]"); |
|
JSONArray easyCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); |
|
for (Object jsonObject : easyCheckerJSON) { |
|
CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); |
|
JSONObject x = (JSONObject) jsonObject; |
|
cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); |
|
cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"))); |
|
cartonUploadMessage.setThreadTime("undefined"); |
|
//这个跟输出到文件中的格式匹配,参考EventDis里的stackTraceToString方法 |
|
String indentation = " "; |
|
String logMessage = x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info")).replaceAll(indentation, "\r\n "); |
|
cartonUploadMessage.setInfo(logMessage); |
|
res.add(cartonUploadMessage); |
|
} |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error("upload fail", e); |
|
} |
|
return res; |
|
} |
|
|
|
private static List<CartonUploadMessage> getEasyFileCartonLog(File file) { |
|
List<CartonUploadMessage> res = new ArrayList<>(); |
|
try { |
|
StringBuilder stringBuilder = new StringBuilder(); |
|
stringBuilder.append("["); |
|
BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); |
|
String line1; |
|
while ((line1 = bufferedReader1.readLine()) != null) { |
|
stringBuilder.append(line1); |
|
} |
|
bufferedReader1.close(); |
|
stringBuilder.append("]"); |
|
JSONArray timerCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); |
|
for (Object jsonObject : timerCheckerJSON) { |
|
JSONObject x = (JSONObject) jsonObject; |
|
CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); |
|
cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); |
|
cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"))); |
|
cartonUploadMessage.setThreadTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"))); |
|
cartonUploadMessage.setInfo("undefined"); |
|
res.add(cartonUploadMessage); |
|
} |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error("upload fail", e); |
|
} |
|
return res; |
|
} |
|
|
|
/** |
|
* /埋点方法上传卡顿信息入口 |
|
* date为 2022-09-08的格式 |
|
*/ |
|
public static List<CartonUploadMessage> uploadJournalLog(Date dateTime) { |
|
List<CartonUploadMessage> res = new ArrayList<>(); |
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
|
CartonFiles files = getFiles(simpleDateFormat.format(dateTime)); |
|
File easyCheckerFile = files.getEasyCheckerFile(); |
|
File timerCheckerFile = files.getTimerCheckerFile(); |
|
if (easyCheckerFile.exists() && timerCheckerFile.exists()) { |
|
return getCartonLog(easyCheckerFile, timerCheckerFile); |
|
} else if (easyCheckerFile.exists()) { |
|
return getEasyFileCartonLog(easyCheckerFile); |
|
} else if (timerCheckerFile.exists()) { |
|
return getTimerFileCartonLog(timerCheckerFile); |
|
} else { |
|
return res; |
|
} |
|
} |
|
|
|
/** |
|
* 初始化监控任务,主要是替换EventQueue以及SwingWorker执行任务的线程池 |
|
*/ |
|
public static void initThreadMonitoring() { |
|
String mainClass = System.getProperty("sun.java.command"); |
|
//判断一下,如果是以Designer4Debug启动,就不注册代码,不然会覆盖掉SwingExplorer,导致其无法使用 |
|
if (!StringUtils.equals(mainClass, DEBUG_MAIN_CLASS_NAME)) { |
|
EventDispatchThreadHangMonitor.initMonitoring(); |
|
AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool()); |
|
} |
|
} |
|
|
|
/** |
|
* 判断是否有指定日期的卡顿日志,没有就返回false |
|
*/ |
|
public static boolean isCartonExists(Date date) { |
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
|
String format = simpleDateFormat.format(date); |
|
Calendar calendar = Calendar.getInstance(); |
|
int month = calendar.get(Calendar.MONTH) + 1; |
|
int year = calendar.get(Calendar.YEAR); |
|
File file = new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month, format)); |
|
return file.exists(); |
|
} |
|
|
|
public static boolean isCartonExists() { |
|
return isCartonExists(new Date()); |
|
} |
|
|
|
private void initSwitchChecker() { |
|
if (easyChecker) { |
|
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true); |
|
} |
|
if (checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.initTimer(); |
|
CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer(); |
|
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true); |
|
} |
|
if (easyChecker || checkerTimerSwitch) { |
|
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); |
|
} |
|
} |
|
|
|
@Override |
|
public void readXML(XMLableReader reader) { |
|
if (reader.isAttr()) { |
|
checkerTimerSwitch = reader.getAttrAsBoolean("checkerTimerSwitch", false); |
|
easyChecker = reader.getAttrAsBoolean("easyChecker", false); |
|
latencyMonitor = reader.getAttrAsBoolean("latencyMonitor", true); |
|
} |
|
try { |
|
initSwitchChecker(); |
|
} catch (Throwable t) { |
|
FineLoggerFactory.getLogger().error("read checker attr fail", t); |
|
} |
|
} |
|
|
|
@Override |
|
public void writeXML(XMLPrintWriter writer) { |
|
writer.startTAG(XML_TAG); |
|
writer.attr("checkerTimerSwitch", checkerTimerSwitch); |
|
writer.attr("easyChecker", easyChecker); |
|
writer.attr("latencyMonitor", latencyMonitor); |
|
writer.end(); |
|
} |
|
|
|
}
|
|
|