Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lakernote
EasyAdmin
提交
07b657b0
E
EasyAdmin
项目概览
lakernote
/
EasyAdmin
10 个月 前同步成功
通知
14
Star
3
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
EasyAdmin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
07b657b0
编写于
10月 17, 2022
作者:
lakernote
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加长事务监控
上级
b1d376f9
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
407 addition
and
2 deletion
+407
-2
src/main/java/com/laker/admin/config/LakerTransactionManagerConfig.java
...com/laker/admin/config/LakerTransactionManagerConfig.java
+27
-0
src/main/java/com/laker/admin/framework/aop/trace/SpanType.java
...in/java/com/laker/admin/framework/aop/trace/SpanType.java
+1
-0
src/main/java/com/laker/admin/framework/aop/trace/Trace.java
src/main/java/com/laker/admin/framework/aop/trace/Trace.java
+2
-0
src/main/java/com/laker/admin/framework/aop/trace/TraceContext.java
...ava/com/laker/admin/framework/aop/trace/TraceContext.java
+11
-2
src/main/java/com/laker/admin/framework/aop/trace/TreeView.java
...in/java/com/laker/admin/framework/aop/trace/TreeView.java
+314
-0
src/main/java/com/laker/admin/framework/ext/transaction/LakerDataSourceTransactionManager.java
...rk/ext/transaction/LakerDataSourceTransactionManager.java
+52
-0
未找到文件。
src/main/java/com/laker/admin/config/LakerTransactionManagerConfig.java
0 → 100644
浏览文件 @
07b657b0
package
com.laker.admin.config
;
import
com.laker.admin.framework.ext.transaction.LakerDataSourceTransactionManager
;
import
org.springframework.beans.factory.ObjectProvider
;
import
org.springframework.boot.autoconfigure.AutoConfigureOrder
;
import
org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.Ordered
;
import
org.springframework.jdbc.datasource.DataSourceTransactionManager
;
import
javax.sql.DataSource
;
@Configuration
@AutoConfigureOrder
(
Ordered
.
LOWEST_PRECEDENCE
)
public
class
LakerTransactionManagerConfig
{
@Bean
DataSourceTransactionManager
transactionManager
(
DataSource
dataSource
,
ObjectProvider
<
TransactionManagerCustomizers
>
transactionManagerCustomizers
)
{
DataSourceTransactionManager
transactionManager
=
new
LakerDataSourceTransactionManager
(
dataSource
);
transactionManagerCustomizers
.
ifAvailable
((
customizers
)
->
customizers
.
customize
(
transactionManager
));
return
transactionManager
;
}
}
src/main/java/com/laker/admin/framework/aop/trace/SpanType.java
浏览文件 @
07b657b0
...
...
@@ -11,5 +11,6 @@ public enum SpanType {
Redis
,
Remote
,
Kafka
,
Transaction
,
Others
;
}
\ No newline at end of file
src/main/java/com/laker/admin/framework/aop/trace/Trace.java
浏览文件 @
07b657b0
...
...
@@ -15,6 +15,8 @@ public class Trace {
*
*/
private
int
depth
=
0
;
private
TreeView
treeView
=
new
TreeView
(
true
,
""
);
/**
* 存储 span结果
*/
...
...
src/main/java/com/laker/admin/framework/aop/trace/TraceContext.java
浏览文件 @
07b657b0
...
...
@@ -2,7 +2,6 @@ package com.laker.admin.framework.aop.trace;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.aspectj.lang.ProceedingJoinPoint
;
import
org.aspectj.lang.reflect.MethodSignature
;
...
...
@@ -46,17 +45,27 @@ public class TraceContext {
span
.
setSpanType
(
spanType
);
span
.
setStartTime
(
System
.
currentTimeMillis
());
trace
.
addSpan
(
span
);
trace
.
getTreeView
().
begin
(
spanType
+
"-"
+
spanName
);
}
public
static
void
stopSpan
()
{
stopSpan
(
1000
);
}
public
static
void
stopSpan
(
long
time
)
{
Trace
trace
=
traceThreadLocal
.
get
();
Span
current
=
trace
.
current
();
current
.
setEndTime
(
System
.
currentTimeMillis
());
current
.
setCost
(
current
.
getEndTime
()
-
current
.
getStartTime
());
trace
.
getTreeView
().
end
();
if
(
trace
.
stopSpan
())
{
if
(
current
.
getCost
()
>
time
)
{
logSpan
(
trace
.
getSpans
(),
StringUtils
.
SPACE
);
// 打印日志方式一
// logSpan(trace.getSpans(), StringUtils.SPACE);
// 打印日志方式二
String
draw
=
trace
.
getTreeView
().
draw
();
log
.
info
(
draw
);
}
traceThreadLocal
.
remove
();
}
...
...
src/main/java/com/laker/admin/framework/aop/trace/TreeView.java
0 → 100644
浏览文件 @
07b657b0
package
com.laker.admin.framework.aop.trace
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
/**
* 树形控件 Created by vlinux on 15/5/26.
* 来自 阿里的arthas中的代码
*/
public
class
TreeView
{
private
static
final
String
STEP_FIRST_CHAR
=
"`---"
;
private
static
final
String
STEP_NORMAL_CHAR
=
"+---"
;
private
static
final
String
STEP_HAS_BOARD
=
"| "
;
private
static
final
String
STEP_EMPTY_BOARD
=
" "
;
private
static
final
String
TIME_UNIT
=
"ms"
;
// 是否输出耗时
private
final
boolean
isPrintCost
;
// 根节点
private
final
Node
root
;
// 当前节点
private
Node
current
;
// 最耗时的节点
private
Node
maxCost
;
public
TreeView
(
boolean
isPrintCost
,
String
title
)
{
this
.
root
=
new
Node
(
title
).
markBegin
().
markEnd
();
this
.
current
=
root
;
this
.
isPrintCost
=
isPrintCost
;
}
public
String
draw
()
{
findMaxCostNode
(
root
);
final
StringBuilder
treeSB
=
new
StringBuilder
();
recursive
(
0
,
true
,
""
,
root
,
new
Callback
()
{
@Override
public
void
callback
(
int
deep
,
boolean
isLast
,
String
prefix
,
Node
node
)
{
treeSB
.
append
(
prefix
).
append
(
isLast
?
STEP_FIRST_CHAR
:
STEP_NORMAL_CHAR
);
if
(
isPrintCost
&&
!
node
.
isRoot
())
{
if
(
node
==
maxCost
)
{
// the node with max cost will be highlighted
treeSB
.
append
(
"[max]:"
+
node
.
toString
().
toString
());
}
else
{
treeSB
.
append
(
node
.
toString
());
}
}
treeSB
.
append
(
node
.
data
);
if
(
node
.
mark
!=
null
&&
node
.
mark
.
length
()
!=
0
)
{
treeSB
.
append
(
" ["
).
append
(
node
.
mark
)
.
append
(
node
.
marks
>
1
?
","
+
node
.
marks
:
""
)
.
append
(
"]"
);
}
treeSB
.
append
(
"\n"
);
}
});
return
treeSB
.
toString
();
}
/**
* 递归遍历
*/
private
void
recursive
(
int
deep
,
boolean
isLast
,
String
prefix
,
Node
node
,
Callback
callback
)
{
callback
.
callback
(
deep
,
isLast
,
prefix
,
node
);
if
(!
node
.
isLeaf
())
{
final
int
size
=
node
.
children
.
size
();
for
(
int
index
=
0
;
index
<
size
;
index
++)
{
final
boolean
isLastFlag
=
index
==
size
-
1
;
final
String
currentPrefix
=
isLast
?
prefix
+
STEP_EMPTY_BOARD
:
prefix
+
STEP_HAS_BOARD
;
recursive
(
deep
+
1
,
isLastFlag
,
currentPrefix
,
node
.
children
.
get
(
index
),
callback
);
}
}
}
/**
* 查找耗时最大的节点,便于后续高亮展示
*
* @param node
*/
private
void
findMaxCostNode
(
Node
node
)
{
if
(!
node
.
isRoot
()
&&
!
node
.
parent
.
isRoot
())
{
if
(
maxCost
==
null
)
{
maxCost
=
node
;
}
else
if
(
maxCost
.
totalCost
<
node
.
totalCost
)
{
maxCost
=
node
;
}
}
if
(!
node
.
isLeaf
())
{
for
(
Node
n
:
node
.
children
)
{
findMaxCostNode
(
n
);
}
}
}
/**
* 创建一个分支节点
*
* @param data 节点数据
* @return this
*/
public
TreeView
begin
(
String
data
)
{
Node
n
=
current
.
find
(
data
);
if
(
n
!=
null
)
{
current
=
n
;
}
else
{
current
=
new
Node
(
current
,
data
);
}
current
.
markBegin
();
return
this
;
}
/**
* 结束一个分支节点
*
* @return this
*/
public
TreeView
end
()
{
if
(
current
.
isRoot
())
{
throw
new
IllegalStateException
(
"current node is root."
);
}
current
.
markEnd
();
current
=
current
.
parent
;
return
this
;
}
/**
* 结束一个分支节点,并带上备注
*
* @return this
*/
public
TreeView
end
(
String
mark
)
{
if
(
current
.
isRoot
())
{
throw
new
IllegalStateException
(
"current node is root."
);
}
current
.
markEnd
().
mark
(
mark
);
current
=
current
.
parent
;
return
this
;
}
/**
* 树节点
*/
private
static
class
Node
{
/**
* 父节点
*/
final
Node
parent
;
/**
* 节点数据
*/
final
String
data
;
/**
* 子节点
*/
final
List
<
Node
>
children
=
new
ArrayList
<
Node
>();
final
Map
<
String
,
Node
>
map
=
new
HashMap
<
String
,
Node
>();
/**
* 开始时间戳
*/
private
long
beginTimestamp
;
/**
* 结束时间戳
*/
private
long
endTimestamp
;
/**
* 备注
*/
private
String
mark
;
/**
* 构造树节点(根节点)
*/
private
Node
(
String
data
)
{
this
.
parent
=
null
;
this
.
data
=
data
;
}
/**
* 构造树节点
*
* @param parent 父节点
* @param data 节点数据
*/
private
Node
(
Node
parent
,
String
data
)
{
this
.
parent
=
parent
;
this
.
data
=
data
;
parent
.
children
.
add
(
this
);
parent
.
map
.
put
(
data
,
this
);
}
/**
* 查找已经存在的节点
*/
Node
find
(
String
data
)
{
return
map
.
get
(
data
);
}
/**
* 是否根节点
*
* @return true / false
*/
boolean
isRoot
()
{
return
null
==
parent
;
}
/**
* 是否叶子节点
*
* @return true / false
*/
boolean
isLeaf
()
{
return
children
.
isEmpty
();
}
Node
markBegin
()
{
beginTimestamp
=
System
.
nanoTime
();
return
this
;
}
Node
markEnd
()
{
endTimestamp
=
System
.
nanoTime
();
long
cost
=
getCost
();
if
(
cost
<
minCost
)
{
minCost
=
cost
;
}
if
(
cost
>
maxCost
)
{
maxCost
=
cost
;
}
times
++;
totalCost
+=
cost
;
return
this
;
}
Node
mark
(
String
mark
)
{
this
.
mark
=
mark
;
marks
++;
return
this
;
}
long
getCost
()
{
return
endTimestamp
-
beginTimestamp
;
}
/**
* convert nano-seconds to milli-seconds
*/
double
getCostInMillis
(
long
nanoSeconds
)
{
return
nanoSeconds
/
1000000.0
;
}
@Override
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
if
(
times
<=
1
)
{
sb
.
append
(
"["
).
append
(
getCostInMillis
(
getCost
()))
.
append
(
TIME_UNIT
).
append
(
"] "
);
}
else
{
sb
.
append
(
"[min="
).
append
(
getCostInMillis
(
minCost
))
.
append
(
TIME_UNIT
).
append
(
",max="
)
.
append
(
getCostInMillis
(
maxCost
)).
append
(
TIME_UNIT
)
.
append
(
",total="
).
append
(
getCostInMillis
(
totalCost
))
.
append
(
TIME_UNIT
).
append
(
",count="
).
append
(
times
)
.
append
(
"] "
);
}
return
sb
.
toString
();
}
/**
* 合并统计相同调用,并计算最小\最大\总耗时
*/
private
long
minCost
=
Long
.
MAX_VALUE
;
private
long
maxCost
=
Long
.
MIN_VALUE
;
private
long
totalCost
=
0
;
private
long
times
=
0
;
private
long
marks
=
0
;
}
/**
* 遍历回调接口
*/
private
interface
Callback
{
void
callback
(
int
deep
,
boolean
isLast
,
String
prefix
,
Node
node
);
}
}
src/main/java/com/laker/admin/framework/ext/transaction/LakerDataSourceTransactionManager.java
0 → 100644
浏览文件 @
07b657b0
package
com.laker.admin.framework.ext.transaction
;
import
cn.hutool.core.date.DateUnit
;
import
cn.hutool.core.date.DateUtil
;
import
com.laker.admin.framework.aop.trace.SpanType
;
import
com.laker.admin.framework.aop.trace.TraceContext
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.jdbc.datasource.DataSourceTransactionManager
;
import
org.springframework.transaction.TransactionDefinition
;
import
javax.sql.DataSource
;
import
java.util.Date
;
/**
* @author: laker
* @date: 2022/10/17
**/
@Slf4j
public
class
LakerDataSourceTransactionManager
extends
DataSourceTransactionManager
{
ThreadLocal
<
Transaction
>
dateThreadLocal
=
new
ThreadLocal
<>();
public
LakerDataSourceTransactionManager
(
DataSource
dataSource
)
{
super
(
dataSource
);
}
@Override
protected
void
doBegin
(
Object
transaction
,
TransactionDefinition
definition
)
{
String
name
=
definition
.
getName
();
TraceContext
.
addSpan
(
"LakerDataSourceTransactionManager.doBegin"
,
SpanType
.
Transaction
);
dateThreadLocal
.
set
(
new
Transaction
(
new
Date
(),
name
));
super
.
doBegin
(
transaction
,
definition
);
}
@Override
protected
void
doCleanupAfterCompletion
(
Object
transaction
)
{
super
.
doCleanupAfterCompletion
(
transaction
);
TraceContext
.
stopSpan
();
Transaction
transactionT
=
dateThreadLocal
.
get
();
log
.
info
(
"transaction:{},time:{}ms"
,
transactionT
.
name
,
DateUtil
.
between
(
new
Date
(),
transactionT
.
begin
,
DateUnit
.
MS
));
dateThreadLocal
.
remove
();
}
class
Transaction
{
Date
begin
;
String
name
;
Transaction
(
Date
begin
,
String
name
)
{
this
.
begin
=
begin
;
this
.
name
=
name
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录