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.
159 lines
5.5 KiB
159 lines
5.5 KiB
package com.fr.design.carton.latency; |
|
|
|
import com.fanruan.third.v2.org.ehcache.impl.internal.concurrent.ConcurrentHashMap; |
|
import com.fr.concurrent.FineExecutors; |
|
import com.fr.concurrent.NamedThreadFactory; |
|
import com.fr.config.MarketConfig; |
|
import com.fr.design.DesignerEnvManager; |
|
import com.fr.design.carton.SwitchForSwingChecker; |
|
import com.fr.design.mainframe.SiteCenterToken; |
|
import com.fr.event.Event; |
|
import com.fr.event.EventDispatcher; |
|
import com.fr.event.Listener; |
|
import com.fr.general.http.HttpToolbox; |
|
import com.fr.json.JSONObject; |
|
import com.fr.stable.ProductConstants; |
|
import com.fr.workspace.WorkContext; |
|
import com.fr.workspace.Workspace; |
|
import com.fr.workspace.WorkspaceEvent; |
|
|
|
import java.util.HashMap; |
|
import java.util.Map; |
|
import java.util.concurrent.ExecutorService; |
|
import java.util.concurrent.Executors; |
|
import java.util.concurrent.ScheduledExecutorService; |
|
import java.util.concurrent.TimeUnit; |
|
import java.util.concurrent.atomic.AtomicInteger; |
|
|
|
import static com.fr.design.carton.CartonConstants.APPID; |
|
import static com.fr.design.carton.CartonConstants.DESIGNER_ID; |
|
import static com.fr.design.carton.CartonConstants.DESIGNER_VERSION; |
|
import static com.fr.design.carton.CartonConstants.DESIGN_METHOD; |
|
import static com.fr.design.carton.CartonConstants.LOCAL; |
|
import static com.fr.design.carton.CartonConstants.OPERANDS_NUM; |
|
import static com.fr.design.carton.CartonConstants.REMOTE; |
|
import static com.fr.design.carton.CartonConstants.TIME; |
|
import static com.fr.design.carton.CartonConstants.USERID; |
|
|
|
/** |
|
* 设计器延迟时间记录Metric |
|
* |
|
* @author Levy.Xie |
|
* @since 11.0 |
|
* Created on 2024/07/01 |
|
*/ |
|
public class DesignerLatencyMetric { |
|
|
|
private ExecutorService executorService; |
|
private ScheduledExecutorService scheduler; |
|
private static final Map<LatencyLevel, AtomicInteger> LATENCY_CONTAINER = new ConcurrentHashMap<>(); |
|
|
|
private static final String LATENCY_INFO_URL = "https://cloud.fanruan.com/api/monitor/record_of_deisgner_latency/single"; |
|
|
|
private final static class InstanceHolder { |
|
static final DesignerLatencyMetric INSTANCE = new DesignerLatencyMetric(); |
|
} |
|
|
|
/** |
|
* 获取单例 |
|
*/ |
|
public static DesignerLatencyMetric getInstance() { |
|
return DesignerLatencyMetric.InstanceHolder.INSTANCE; |
|
} |
|
|
|
private DesignerLatencyMetric() { |
|
} |
|
|
|
/** |
|
* 启动 |
|
*/ |
|
public void start() { |
|
if (SwitchForSwingChecker.isLatencyMonitoring()) { |
|
// 初始化容器 |
|
initializeContainer(); |
|
// 启动异步性能记录线程池 |
|
executorService = FineExecutors.newCachedThreadPool( |
|
new NamedThreadFactory(DesignerLatencyMetric.class)); |
|
// 启动定时埋点 |
|
this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("LatencyMetricWorker")); |
|
this.scheduler.scheduleWithFixedDelay(this::collectAndSubmit, 60, 60, TimeUnit.SECONDS); |
|
// 注册设计器工作目录切换事件监听 |
|
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() { |
|
@Override |
|
public void on(Event event, Workspace param) { |
|
collectAndSubmit(); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
/** |
|
* 关闭 |
|
*/ |
|
public void stop() { |
|
if (SwitchForSwingChecker.isLatencyMonitoring()) { |
|
if (this.executorService != null) { |
|
this.executorService.shutdown(); |
|
} |
|
if (this.scheduler != null) { |
|
this.scheduler.shutdown(); |
|
} |
|
collectAndSubmit(); |
|
} |
|
} |
|
|
|
private void initializeContainer() { |
|
for (LatencyLevel level : LatencyLevel.values()) { |
|
LATENCY_CONTAINER.put(level, new AtomicInteger()); |
|
} |
|
} |
|
|
|
private void resetContainer() { |
|
LATENCY_CONTAINER.values().forEach(count -> count.set(0)); |
|
} |
|
|
|
/** |
|
* 记录性能信息 |
|
*/ |
|
public void record(long cost) { |
|
executorService.submit(() -> { |
|
try { |
|
LatencyLevel level = LatencyLevel.measure(cost); |
|
LATENCY_CONTAINER.computeIfAbsent(level, k -> new AtomicInteger()).incrementAndGet(); |
|
} catch (Throwable ignore) { |
|
// 记录失败不影响业务 |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* 汇总并提交性能监控埋点 |
|
*/ |
|
public void collectAndSubmit() { |
|
Map<String, Object> para = new HashMap<>(); |
|
para.put("token", SiteCenterToken.generateToken()); |
|
para.put("content", collect()); |
|
try { |
|
HttpToolbox.post(LATENCY_INFO_URL, para); |
|
} catch (Throwable ignore) { |
|
// doNothing |
|
} |
|
resetContainer(); |
|
} |
|
|
|
private JSONObject collect() { |
|
JSONObject info = new JSONObject(); |
|
info.put(TIME, System.currentTimeMillis()); |
|
info.put(APPID, MarketConfig.getInstance().getCloudOperationMaintenanceId()); |
|
info.put(USERID, MarketConfig.getInstance().getBbsUid()); |
|
info.put(DESIGNER_ID, DesignerEnvManager.getEnvManager().getUUID()); |
|
info.put(DESIGNER_VERSION, ProductConstants.DESIGNER_VERSION); |
|
info.put(DESIGN_METHOD, WorkContext.getCurrent().isLocal() ? LOCAL : REMOTE); |
|
info.put(OPERANDS_NUM, LATENCY_CONTAINER.values().stream().mapToInt(AtomicInteger::get).sum()); |
|
for (Map.Entry<LatencyLevel, AtomicInteger> entry : LATENCY_CONTAINER.entrySet()) { |
|
info.put(entry.getKey().getMark(), entry.getValue().get()); |
|
} |
|
return info; |
|
} |
|
|
|
}
|
|
|