sviolet.slate.common.x.monitor.txtimer.TxTimer Maven / Gradle / Ivy
Show all versions of slate-txtimer Show documentation
/*
* Copyright (C) 2015-2018 S.Violet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project GitHub: https://github.com/shepherdviolet/slate
* Email: [email protected]
*/
package sviolet.slate.common.x.monitor.txtimer;
import com.github.shepherdviolet.glaciion.Glaciion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
/**
* 简单的交易耗时统计, 提供默认实现, 也可以用Glaciion SPI扩展
*
* 日志前缀:TxTimer
*
* 启动参数:
* -Dslate.txtimer.enabled=true 启用统计, true开启, false关闭, 默认开启
*
*
* 默认实现 ********************************************************************************************
*
*
* 1.默认实现了交易耗时的统计, 并通过日志定时输出报告.
* 2.可以使用Glaciion SPI替换实现, 替换实现后下面的参数无效.
*
*
* 默认实现的启动参数(不可动态修改):
* -Dslate.txtimer.report.interval=5 日志报告输出间隔, 单位分钟, [2-60], 默认5
* -Dslate.txtimer.pagelines=20 日志每次输出的最大行数, 大于该行数会分页, 默认20
*
*
* 默认实现的启动参数(可动态修改):
* -Dslate.txtimer.reportall.interval=60 全量日志报告输出间隔(周期), 单位:分钟, [2-∞], 默认∞(不输出全量日志)
* -Dslate.txtimer.threshold.avg=2000 打印周期内平均耗时超过该值的交易, 单位:毫秒
* -Dslate.txtimer.threshold.max=10000 打印周期内最大耗时超过该值的交易, 单位:毫秒
* -Dslate.txtimer.threshold.min=1000 打印周期内最小耗时超过该值的交易, 单位:毫秒
*
*
* slate.txtimer.threshold系列参数均未配置, 则输出全部交易的报告. 若设置了任意一个, 则只有满足条件的交易才输出:
* avg >= thresholdAvg || max >= thresholdMax || min >= thresholdMin
*
* @author S.Violet
*/
public class TxTimer {
private static final Logger logger = LoggerFactory.getLogger(TxTimer.class);
private static final TxTimerProvider2 PROVIDER;
static {
//统计开关, 默认关闭
if ("true".equals(System.getProperty("slate.txtimer.enabled", "true"))) {
TxTimerProvider2 service = Glaciion.loadSingleService(TxTimerProvider2.class).get();
//再根据provider判断是否要启用
if (service.enabled()) {
PROVIDER = service;
logger.info("TxTimer | TxTimer Enabled !!! implementation " + PROVIDER.getClass().getName());
} else {
PROVIDER = null;
}
} else {
PROVIDER = null;
}
}
/**
* 交易开始时调用
*
*
* try (TimerContext context = TxTimer.entry("Entrance", "TestService")) {
* // 交易逻辑 ......
* }
*
*
*
* TimerContext context = TxTimer.entry("Entrance", "TestService");
* try {
* // 交易逻辑 ......
* } finally {
* context.exit();
* }
*
*
* @param groupName 组别
* @param transactionName 交易名
*/
public static TimerContext entry(String groupName, String transactionName){
if (PROVIDER != null) {
return PROVIDER.entry(groupName, transactionName);
}
return DUMMY_CONTEXT;
}
/**
* 交易结束时调用
*
*
* try (TimerContext context = TxTimer.entry("Entrance", "TestService")) {
* // 交易逻辑 ......
* }
*
*
*
* TimerContext context = TxTimer.entry("Entrance", "TestService");
* try {
* // 交易逻辑 ......
* } finally {
* //context.exit();
* TxTimer.exit(context);
* }
*
*
* @param timerContext 处理结果编码
*/
public static void exit(TimerContext timerContext) {
exit(timerContext, 0);
}
/**
* 交易结束时调用
*
*
* try (TimerContext context = TxTimer.entry("Entrance", "TestService")) {
* // 交易逻辑 ......
* }
*
*
*
* TimerContext context = TxTimer.entry("Entrance", "TestService");
* try {
* // 交易逻辑 ......
* } finally {
* //context.exit(code);
* TxTimer.exit(context, code);
* }
*
*
* @param timerContext 处理结果编码
*/
public static void exit(TimerContext timerContext, int resultCode) {
if (timerContext == DUMMY_CONTEXT) {
return;
}
if (PROVIDER != null) {
PROVIDER.exit(timerContext, resultCode);
}
}
public static TxTimerProvider2 getProvider(){
if (PROVIDER != null && PROVIDER.canBeGet()) {
return PROVIDER;
}
logger.error("TxTimer | Prohibit access to get TxTimerProvider2, Null or Banned by TxTimerProvider2.canBeGet()");
return null;
}
private static final TimerContext DUMMY_CONTEXT = new TimerContext.Basic(){
@Override
public void exit(int resultCode) {
//do nothing
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Deprecated ///////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//用于start和stop之间的上下文传递
private static final ThreadLocal> recordStack = new ThreadLocal<>();
/**
* 交易开始时调用, 弃用, 这个只能统计同步的代码块
*
*
* try {
* TxTimer.start("Entrance", "TestService");
* // 交易逻辑 ......
* } finally {
* TxTimer.stop();
* }
*
*
* @param groupName 组别
* @param transactionName 交易名
* @deprecated TxTimer#entry + TxTimer#exit instead
*/
@Deprecated
public static void start(String groupName, String transactionName){
if (PROVIDER != null) {
TimerContext timerContext = PROVIDER.entry(groupName, transactionName);
//从ThreadLocal获取上下文
LinkedList recordStack = TxTimer.recordStack.get();
if (recordStack == null) {
recordStack = new LinkedList<>();
TxTimer.recordStack.set(recordStack);
}
//存入堆栈
recordStack.addLast(timerContext);
}
}
/**
* 交易结束时调用, 弃用, 这个只能统计同步的代码块
*
*
* try {
* TxTimer.start("Entrance", "TestService");
* // 交易逻辑 ......
* } finally {
* TxTimer.stop();
* }
*
*
* @deprecated TxTimer#entry + TxTimer#exit instead
*/
@Deprecated
public static void stop(){
stop(0);
}
/**
* 交易结束时调用, 弃用, 这个只能统计同步的代码块
*
*
* try {
* TxTimer.start("Entrance", "TestService");
* // 交易逻辑 ......
* } finally {
* TxTimer.stop();
* }
*
*
* @param resultCode 处理结果编码
* @deprecated TxTimer#entry + TxTimer#exit instead
*/
@Deprecated
public static void stop(int resultCode){
if (PROVIDER != null) {
//从ThreadLocal获取上下文, 若不存在则不正常
LinkedList recordStack = TxTimer.recordStack.get();
if (recordStack == null) {
return;
}
TimerContext timerContext = recordStack.pollLast();
//如果栈里没记录, 则删除栈
if (recordStack.size() <= 0) {
TxTimer.recordStack.remove();
}
PROVIDER.exit(timerContext, resultCode);
}
}
}