Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
山不在高_有仙则灵
SkyWalking
提交
14f9154b
S
SkyWalking
项目概览
山不在高_有仙则灵
/
SkyWalking
与 Fork 源项目一致
Fork自
apache / SkyWalking
通知
12
Star
0
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
SkyWalking
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
14f9154b
编写于
6月 09, 2017
作者:
wu-sheng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix some test cases.
上级
ae9bc45c
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
289 addition
and
86 deletion
+289
-86
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/BooleanTagReader.java
...t/java/org/skywalking/apm/trace/tag/BooleanTagReader.java
+5
-3
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/IntTagReader.java
.../test/java/org/skywalking/apm/trace/tag/IntTagReader.java
+5
-3
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/TagsTest.java
.../src/test/java/org/skywalking/apm/trace/tag/TagsTest.java
+3
-3
apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/EnhancedClassInstanceContext.java
...core/plugin/interceptor/EnhancedClassInstanceContext.java
+0
-11
apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/assist/NoConcurrencyAccessObject.java
.../plugin/interceptor/assist/NoConcurrencyAccessObject.java
+2
-4
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/LeafSpanTestCase.java
...g/skywalking/apm/agent/core/context/LeafSpanTestCase.java
+9
-4
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/TracerContextTestCase.java
...walking/apm/agent/core/context/TracerContextTestCase.java
+2
-2
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/plugin/interceptor/EnhancedClassInstanceContextTest.java
.../plugin/interceptor/EnhancedClassInstanceContextTest.java
+1
-1
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/BooleanTagReader.java
.../org/skywalking/apm/agent/core/tags/BooleanTagReader.java
+33
-0
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/IntTagReader.java
...java/org/skywalking/apm/agent/core/tags/IntTagReader.java
+33
-0
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/StringTagReader.java
...a/org/skywalking/apm/agent/core/tags/StringTagReader.java
+33
-0
apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java
...lugin/httpClient/v4/HttpClientExecuteInterceptorTest.java
+23
-8
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/AbstractStatementTest.java
...org/skywalking/apm/plugin/jdbc/AbstractStatementTest.java
+14
-4
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWCallableStatementTest.java
...g/skywalking/apm/plugin/jdbc/SWCallableStatementTest.java
+15
-2
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWConnectionTest.java
...java/org/skywalking/apm/plugin/jdbc/SWConnectionTest.java
+28
-4
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWStatementTest.java
.../java/org/skywalking/apm/plugin/jdbc/SWStatementTest.java
+12
-2
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SwPreparedStatementTest.java
...g/skywalking/apm/plugin/jdbc/SwPreparedStatementTest.java
+17
-2
apm-sniffer/apm-sdk-plugin/jedis-2.x-plugin/src/main/java/org/skywalking/apm/plugin/jedis/v2/JedisMethodInterceptor.java
...kywalking/apm/plugin/jedis/v2/JedisMethodInterceptor.java
+19
-12
apm-sniffer/apm-sdk-plugin/jedis-2.x-plugin/src/test/java/org/skywalking/apm/plugin/jedis/v2/JedisMethodInterceptorTest.java
...lking/apm/plugin/jedis/v2/JedisMethodInterceptorTest.java
+35
-21
未找到文件。
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/BooleanTagReader.java
浏览文件 @
14f9154b
...
...
@@ -20,9 +20,11 @@ public class BooleanTagReader {
e
.
printStackTrace
();
}
for
(
BooleanTagItem
item
:
tagsWithBoolList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
if
(
tagsWithBoolList
!=
null
)
{
for
(
BooleanTagItem
item
:
tagsWithBoolList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
}
}
}
return
tag
.
defaultValue
();
...
...
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/IntTagReader.java
浏览文件 @
14f9154b
...
...
@@ -20,9 +20,11 @@ public class IntTagReader {
e
.
printStackTrace
();
}
for
(
IntTagItem
item
:
tagsWithIntList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
if
(
tagsWithIntList
!=
null
)
{
for
(
IntTagItem
item
:
tagsWithIntList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
}
}
}
return
null
;
...
...
apm-commons/apm-trace/src/test/java/org/skywalking/apm/trace/tag/TagsTest.java
浏览文件 @
14f9154b
...
...
@@ -14,9 +14,11 @@ public class TagsTest {
Tags
.
SPAN_LAYER
.
asDB
(
span
);
Assert
.
assertEquals
(
"db"
,
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
));
span
=
new
Span
(
1
,
"/test"
);
Tags
.
SPAN_LAYER
.
asRPCFramework
(
span
);
Assert
.
assertEquals
(
"rpc"
,
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
));
span
=
new
Span
(
1
,
"/test"
);
Tags
.
SPAN_LAYER
.
asHttp
(
span
);
Assert
.
assertEquals
(
"http"
,
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
));
}
...
...
@@ -27,6 +29,7 @@ public class TagsTest {
Span
span
=
new
Span
(
1
,
"/test"
);
Assert
.
assertFalse
(
BooleanTagReader
.
get
(
span
,
tag
));
span
=
new
Span
(
1
,
"/test"
);
tag
.
set
(
span
,
true
);
Assert
.
assertTrue
(
BooleanTagReader
.
get
(
span
,
tag
));
}
...
...
@@ -36,8 +39,5 @@ public class TagsTest {
IntTag
tag
=
new
IntTag
(
"test.key"
);
Span
span
=
new
Span
(
1
,
"/test"
);
Assert
.
assertNull
(
IntTagReader
.
get
(
span
,
tag
));
tag
.
set
(
span
,
123
);
Assert
.
assertEquals
(
123
,
IntTagReader
.
get
(
span
,
tag
).
intValue
());
}
}
apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/EnhancedClassInstanceContext.java
浏览文件 @
14f9154b
...
...
@@ -53,15 +53,4 @@ public class EnhancedClassInstanceContext {
return
context
.
containsKey
(
key
);
}
/**
* get an stored instance, if it is existed.
*
* @param key
* @param type
* @param <T> expected stored instance's type
* @return null or stored instance.
*/
public
<
T
>
T
get
(
Object
key
,
Class
<
T
>
type
)
{
return
(
T
)
this
.
get
(
key
);
}
}
apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/assist/NoConcurrencyAccessObject.java
浏览文件 @
14f9154b
...
...
@@ -22,8 +22,7 @@ public abstract class NoConcurrencyAccessObject {
if
(!
context
.
isContain
(
INVOKE_COUNTER_KEY
))
{
context
.
set
(
INVOKE_COUNTER_KEY
,
0
);
}
int
counter
=
context
.
get
(
INVOKE_COUNTER_KEY
,
Integer
.
class
);
int
counter
=
(
Integer
)
context
.
get
(
INVOKE_COUNTER_KEY
);
if
(++
counter
==
1
)
{
enter
(
context
,
interceptorContext
);
}
...
...
@@ -35,8 +34,7 @@ public abstract class NoConcurrencyAccessObject {
throw
new
InterceptorException
(
"key=INVOKE_COUNTER_KEY not found is context. unexpected situation."
);
}
int
counter
=
context
.
get
(
INVOKE_COUNTER_KEY
,
Integer
.
class
);
int
counter
=
(
Integer
)
context
.
get
(
INVOKE_COUNTER_KEY
);
if
(--
counter
==
0
)
{
exit
();
}
...
...
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/LeafSpanTestCase.java
浏览文件 @
14f9154b
package
org.skywalking.apm.agent.core.context
;
import
java.util.Map
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
org.skywalking.apm.agent.core.tags.BooleanTagReader
;
import
org.skywalking.apm.agent.core.tags.IntTagReader
;
import
org.skywalking.apm.agent.core.tags.StringTagReader
;
import
org.skywalking.apm.trace.tag.BooleanTag
;
import
org.skywalking.apm.trace.tag.IntTag
;
import
org.skywalking.apm.trace.tag.StringTag
;
/**
* @author wusheng
...
...
@@ -27,9 +32,9 @@ public class LeafSpanTestCase {
span
.
setTag
(
"key2"
,
true
);
span
.
setTag
(
"key3"
,
2
);
Assert
.
assertEquals
(
"serviceA2"
,
span
.
getOperationName
());
Assert
.
assertEquals
(
"value-text"
,
span
.
getStrTag
(
"key"
));
Assert
.
assertFalse
(
span
.
getBoolTag
(
"key2"
));
Assert
.
assertEquals
(
1
,
span
.
getIntTag
(
"key3"
).
intValue
());
Assert
.
assertEquals
(
"value-text"
,
StringTagReader
.
get
(
span
,
new
StringTag
(
"key"
)
));
Assert
.
assertFalse
(
BooleanTagReader
.
get
(
span
,
new
BooleanTag
(
"key2"
,
false
)
));
Assert
.
assertEquals
(
1
,
IntTagReader
.
get
(
span
,
new
IntTag
(
"key3"
)
).
intValue
());
//end 2nd span
span
.
pop
();
...
...
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/TracerContextTestCase.java
浏览文件 @
14f9154b
...
...
@@ -62,8 +62,8 @@ public class TracerContextTestCase {
TracerContext
context
=
new
TracerContext
();
Span
serviceSpan
=
context
.
createSpan
(
"/serviceA"
,
false
);
Span
dbSpan
=
context
.
createSpan
(
"db/preparedStatement/execute"
,
false
);
Tags
.
PEER_HOST
.
set
(
dbSpan
,
"127.0.0.1"
);
Tags
.
PEER_PORT
.
set
(
dbSpan
,
8080
);
dbSpan
.
setPeerHost
(
"127.0.0.1"
);
dbSpan
.
setPort
(
8080
);
ContextCarrier
carrier
=
new
ContextCarrier
();
context
.
inject
(
carrier
);
...
...
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/plugin/interceptor/EnhancedClassInstanceContextTest.java
浏览文件 @
14f9154b
...
...
@@ -13,6 +13,6 @@ public class EnhancedClassInstanceContextTest {
context
.
set
(
"key"
,
"value"
);
Assert
.
assertTrue
(
context
.
isContain
(
"key"
));
Assert
.
assertEquals
(
"value"
,
context
.
get
(
"key"
));
Assert
.
assertEquals
(
"value"
,
context
.
get
(
"key"
,
String
.
class
));
Assert
.
assertEquals
(
"value"
,
(
String
)
context
.
get
(
"key"
));
}
}
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/BooleanTagReader.java
0 → 100644
浏览文件 @
14f9154b
package
org.skywalking.apm.agent.core.tags
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.tag.BooleanTag
;
import
org.skywalking.apm.trace.tag.BooleanTagItem
;
/**
* @author wusheng
*/
public
class
BooleanTagReader
{
public
static
Boolean
get
(
Span
span
,
BooleanTag
tag
)
{
List
<
BooleanTagItem
>
tagsWithBoolList
=
null
;
try
{
Field
tagsWithBool
=
Span
.
class
.
getDeclaredField
(
"tagsWithBool"
);
tagsWithBool
.
setAccessible
(
true
);
tagsWithBoolList
=
(
List
<
BooleanTagItem
>)
tagsWithBool
.
get
(
span
);
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchFieldException
e
)
{
e
.
printStackTrace
();
}
for
(
BooleanTagItem
item
:
tagsWithBoolList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
}
}
return
tag
.
defaultValue
();
}
}
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/IntTagReader.java
0 → 100644
浏览文件 @
14f9154b
package
org.skywalking.apm.agent.core.tags
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.tag.IntTag
;
import
org.skywalking.apm.trace.tag.IntTagItem
;
/**
* @author wusheng
*/
public
class
IntTagReader
{
public
static
Integer
get
(
Span
span
,
IntTag
tag
)
{
List
<
IntTagItem
>
tagsWithIntList
=
null
;
try
{
Field
tagsWithInt
=
Span
.
class
.
getDeclaredField
(
"tagsWithInt"
);
tagsWithInt
.
setAccessible
(
true
);
tagsWithIntList
=
(
List
<
IntTagItem
>)
tagsWithInt
.
get
(
span
);
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchFieldException
e
)
{
e
.
printStackTrace
();
}
for
(
IntTagItem
item
:
tagsWithIntList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
}
}
return
null
;
}
}
apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/tags/StringTagReader.java
0 → 100644
浏览文件 @
14f9154b
package
org.skywalking.apm.agent.core.tags
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.tag.StringTag
;
import
org.skywalking.apm.trace.tag.StringTagItem
;
/**
* @author wusheng
*/
public
class
StringTagReader
{
public
static
String
get
(
Span
span
,
StringTag
tag
)
{
List
<
StringTagItem
>
tagsWithStrList
=
null
;
try
{
Field
tagsWithStr
=
Span
.
class
.
getDeclaredField
(
"tagsWithStr"
);
tagsWithStr
.
setAccessible
(
true
);
tagsWithStrList
=
(
List
<
StringTagItem
>)
tagsWithStr
.
get
(
span
);
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchFieldException
e
)
{
e
.
printStackTrace
();
}
for
(
StringTagItem
item
:
tagsWithStrList
)
{
if
(
tag
.
key
().
equals
(
item
.
getKey
()))
{
return
item
.
getValue
();
}
}
return
null
;
}
}
apm-sniffer/apm-sdk-plugin/httpClient-4.x-plugin/src/test/java/org/skywalking/apm/plugin/httpClient/v4/HttpClientExecuteInterceptorTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.httpClient.v4
;
import
java.lang.reflect.Field
;
import
org.apache.http.*
;
import
org.junit.After
;
import
org.junit.Before
;
...
...
@@ -15,6 +16,8 @@ import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceCon
import
org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.context.SegmentAssert
;
import
org.skywalking.apm.sniffer.mock.trace.tags.BooleanTagReader
;
import
org.skywalking.apm.sniffer.mock.trace.tags.StringTagReader
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.TraceSegment
;
...
...
@@ -108,7 +111,7 @@ public class HttpClientExecuteInterceptorTest {
public
void
call
(
TraceSegment
traceSegment
)
{
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
assertHttpSpan
(
traceSegment
.
getSpans
().
get
(
0
));
assertThat
(
Tags
.
ERROR
.
get
(
traceSegment
.
getSpans
().
get
(
0
)
),
is
(
true
));
assertThat
(
BooleanTagReader
.
get
(
traceSegment
.
getSpans
().
get
(
0
),
Tags
.
ERROR
),
is
(
true
));
verify
(
request
,
times
(
1
)).
setHeader
(
anyString
(),
anyString
());
}
});
...
...
@@ -127,8 +130,14 @@ public class HttpClientExecuteInterceptorTest {
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
Span
span
=
traceSegment
.
getSpans
().
get
(
0
);
assertHttpSpan
(
span
);
assertThat
(
Tags
.
ERROR
.
get
(
span
),
is
(
true
));
assertHttpSpanErrorLog
(
span
.
getLogs
());
assertThat
(
BooleanTagReader
.
get
(
span
,
Tags
.
ERROR
),
is
(
true
));
try
{
assertHttpSpanErrorLog
(
getLogs
(
span
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
verify
(
request
,
times
(
1
)).
setHeader
(
anyString
(),
anyString
());
}
...
...
@@ -144,11 +153,11 @@ public class HttpClientExecuteInterceptorTest {
private
void
assertHttpSpan
(
Span
span
)
{
assertThat
(
span
.
getOperationName
(),
is
(
"/test-web/test"
));
assertThat
(
Tags
.
COMPONENT
.
get
(
span
),
is
(
"HttpClient"
));
assertThat
(
Tags
.
PEER_HOST
.
get
(
span
),
is
(
"127.0.0.1"
));
assertThat
(
Tags
.
PEER_PORT
.
get
(
span
),
is
(
8080
));
assertThat
(
Tags
.
URL
.
get
(
span
),
is
(
"http://127.0.0.1:8080/test-web/test"
));
assertThat
(
Tags
.
SPAN_KIND
.
get
(
span
),
is
(
Tags
.
SPAN_KIND_CLIENT
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
COMPONENT
),
is
(
"HttpClient"
));
assertThat
(
span
.
getPeerHost
(
),
is
(
"127.0.0.1"
));
assertThat
(
span
.
getPort
(
),
is
(
8080
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
URL
),
is
(
"http://127.0.0.1:8080/test-web/test"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
SPAN_KIND
),
is
(
Tags
.
SPAN_KIND_CLIENT
));
}
@After
...
...
@@ -156,4 +165,10 @@ public class HttpClientExecuteInterceptorTest {
TracerContext
.
ListenerManager
.
remove
(
mockTracerContextListener
);
}
protected
List
<
LogData
>
getLogs
(
Span
span
)
throws
NoSuchFieldException
,
IllegalAccessException
{
Field
logs
=
Span
.
class
.
getDeclaredField
(
"logs"
);
logs
.
setAccessible
(
true
);
return
(
List
<
LogData
>)
logs
.
get
(
span
);
}
}
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/AbstractStatementTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.jdbc
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.hamcrest.CoreMatchers
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.trace.tags.StringTagReader
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.tag.Tags
;
...
...
@@ -25,13 +28,20 @@ public abstract class AbstractStatementTest {
protected
void
assertDBSpan
(
Span
span
,
String
exceptOperationName
,
String
exceptDBStatement
)
{
assertDBSpan
(
span
,
exceptOperationName
);
assertThat
(
Tags
.
DB_STATEMENT
.
get
(
span
),
is
(
exceptDBStatement
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_STATEMENT
),
is
(
exceptDBStatement
));
}
protected
void
assertDBSpan
(
Span
span
,
String
exceptOperationName
)
{
assertThat
(
span
.
getOperationName
(),
is
(
exceptOperationName
));
assertThat
(
Tags
.
COMPONENT
.
get
(
span
),
is
(
"Mysql"
));
assertThat
(
Tags
.
DB_INSTANCE
.
get
(
span
),
is
(
"test"
));
assertT
rue
(
Tags
.
SPAN_LAYER
.
isDB
(
span
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
COMPONENT
),
is
(
"Mysql"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_INSTANCE
),
is
(
"test"
));
assertT
hat
(
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
),
is
(
"db"
));
}
protected
List
<
LogData
>
getLogs
(
Span
span
)
throws
NoSuchFieldException
,
IllegalAccessException
{
Field
logs
=
Span
.
class
.
getDeclaredField
(
"logs"
);
logs
.
setAccessible
(
true
);
return
(
List
<
LogData
>)
logs
.
get
(
span
);
}
}
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWCallableStatementTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.jdbc
;
import
com.mysql.cj.api.jdbc.JdbcConnection
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.hamcrest.CoreMatchers
;
import
org.junit.After
;
import
org.junit.Assert
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -13,6 +16,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager;
import
org.skywalking.apm.agent.core.context.TracerContext
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.context.SegmentAssert
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.TraceSegment
;
...
...
@@ -715,8 +719,16 @@ public class SWCallableStatementTest extends AbstractStatementTest {
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
Span
span
=
traceSegment
.
getSpans
().
get
(
0
);
assertDBSpan
(
span
,
"Mysql/JDBI/CallableStatement/executeQuery"
,
"SELECT * FROM test WHERE a = ? or b = ? or c=? or d = ? or e=?"
);
assertThat
(
span
.
getLogs
().
size
(),
is
(
1
));
assertDBSpanLog
(
span
.
getLogs
().
get
(
0
));
try
{
List
<
LogData
>
logData
=
getLogs
(
span
);
Assert
.
assertThat
(
logData
.
size
(),
is
(
1
));
assertThat
(
logData
.
size
(),
is
(
1
));
assertDBSpanLog
(
logData
.
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
@@ -727,4 +739,5 @@ public class SWCallableStatementTest extends AbstractStatementTest {
TracerContext
.
ListenerManager
.
remove
(
mockTracerContextListener
);
}
}
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWConnectionTest.java
浏览文件 @
14f9154b
...
...
@@ -97,7 +97,13 @@ public class SWConnectionTest extends AbstractStatementTest {
public
void
call
(
TraceSegment
traceSegment
)
{
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
assertDBSpan
(
traceSegment
.
getSpans
().
get
(
0
),
"Mysql/JDBI/Connection/commit"
);
assertDBSpanLog
(
traceSegment
.
getSpans
().
get
(
0
).
getLogs
().
get
(
0
));
try
{
assertDBSpanLog
(
getLogs
(
traceSegment
.
getSpans
().
get
(
0
)).
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
@@ -190,7 +196,13 @@ public class SWConnectionTest extends AbstractStatementTest {
public
void
call
(
TraceSegment
traceSegment
)
{
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
assertDBSpan
(
traceSegment
.
getSpans
().
get
(
0
),
"Mysql/JDBI/Connection/rollback to savepoint"
);
assertDBSpanLog
(
traceSegment
.
getSpans
().
get
(
0
).
getLogs
().
get
(
0
));
try
{
assertDBSpanLog
(
getLogs
(
traceSegment
.
getSpans
().
get
(
0
)).
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
@@ -236,7 +248,13 @@ public class SWConnectionTest extends AbstractStatementTest {
public
void
call
(
TraceSegment
traceSegment
)
{
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
assertDBSpan
(
traceSegment
.
getSpans
().
get
(
0
),
"Mysql/JDBI/Connection/close"
);
assertDBSpanLog
(
traceSegment
.
getSpans
().
get
(
0
).
getLogs
().
get
(
0
));
try
{
assertDBSpanLog
(
getLogs
(
traceSegment
.
getSpans
().
get
(
0
)).
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
@@ -282,7 +300,13 @@ public class SWConnectionTest extends AbstractStatementTest {
public
void
call
(
TraceSegment
traceSegment
)
{
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
assertDBSpan
(
traceSegment
.
getSpans
().
get
(
0
),
"Mysql/JDBI/Connection/releaseSavepoint savepoint"
);
assertDBSpanLog
(
traceSegment
.
getSpans
().
get
(
0
).
getLogs
().
get
(
0
));
try
{
assertDBSpanLog
(
getLogs
(
traceSegment
.
getSpans
().
get
(
0
)).
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SWStatementTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.jdbc
;
import
com.mysql.cj.api.jdbc.JdbcConnection
;
import
java.util.List
;
import
org.hamcrest.CoreMatchers
;
import
org.junit.After
;
import
org.junit.Before
;
...
...
@@ -12,6 +13,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager;
import
org.skywalking.apm.agent.core.context.TracerContext
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.context.SegmentAssert
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.TraceSegment
;
...
...
@@ -290,8 +292,16 @@ public class SWStatementTest extends AbstractStatementTest {
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
Span
span
=
traceSegment
.
getSpans
().
get
(
0
);
assertDBSpan
(
span
,
"Mysql/JDBI/Statement/execute"
,
"UPDATE test SET a = 1 WHERE b = 2"
);
assertThat
(
span
.
getLogs
().
size
(),
is
(
1
));
assertDBSpanLog
(
span
.
getLogs
().
get
(
0
));
List
<
LogData
>
logs
=
null
;
try
{
logs
=
getLogs
(
span
);
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
assertThat
(
logs
.
size
(),
is
(
1
));
assertDBSpanLog
(
logs
.
get
(
0
));
}
});
}
...
...
apm-sniffer/apm-sdk-plugin/jdbc-plugin/src/test/java/org/skywalking/apm/plugin/jdbc/SwPreparedStatementTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.jdbc
;
import
com.mysql.cj.api.jdbc.JdbcConnection
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.hamcrest.CoreMatchers
;
import
org.junit.After
;
import
org.junit.Assert
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -13,6 +16,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager;
import
org.skywalking.apm.agent.core.context.TracerContext
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.context.SegmentAssert
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.TraceSegment
;
...
...
@@ -549,8 +553,19 @@ public class SwPreparedStatementTest extends AbstractStatementTest {
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
Span
span
=
traceSegment
.
getSpans
().
get
(
0
);
assertDBSpan
(
span
,
"Mysql/JDBI/PreparedStatement/executeQuery"
,
"SELECT * FROM test WHERE a = ? or b = ? or c=? or d = ? or e=?"
);
assertThat
(
span
.
getLogs
().
size
(),
is
(
1
));
assertDBSpanLog
(
span
.
getLogs
().
get
(
0
));
try
{
Field
logs
=
Span
.
class
.
getDeclaredField
(
"logs"
);
logs
.
setAccessible
(
true
);
List
<
LogData
>
logData
=
(
List
<
LogData
>)
logs
.
get
(
span
);
Assert
.
assertThat
(
logData
.
size
(),
is
(
1
));
assertThat
(
logData
.
size
(),
is
(
1
));
assertDBSpanLog
(
logData
.
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
apm-sniffer/apm-sdk-plugin/jedis-2.x-plugin/src/main/java/org/skywalking/apm/plugin/jedis/v2/JedisMethodInterceptor.java
浏览文件 @
14f9154b
...
...
@@ -6,9 +6,9 @@ import org.skywalking.apm.agent.core.plugin.interceptor.assist.NoConcurrencyAcce
import
org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext
;
import
org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor
;
import
org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult
;
import
org.skywalking.apm.util.StringUtil
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.tag.Tags
;
import
org.skywalking.apm.util.StringUtil
;
/**
* {@link JedisMethodInterceptor} intercept all method of {@link redis.clients.jedis.Jedis}
...
...
@@ -43,7 +43,7 @@ public class JedisMethodInterceptor extends NoConcurrencyAccessObject implements
@Override
public
void
beforeMethod
(
final
EnhancedClassInstanceContext
context
,
final
InstanceMethodInvokeContext
interceptorContext
,
MethodInterceptResult
result
)
{
final
InstanceMethodInvokeContext
interceptorContext
,
MethodInterceptResult
result
)
{
this
.
whenEnter
(
context
,
interceptorContext
);
}
...
...
@@ -51,25 +51,28 @@ public class JedisMethodInterceptor extends NoConcurrencyAccessObject implements
* set peer host information for the current active span.
*/
private
void
tagPeer
(
Span
span
,
EnhancedClassInstanceContext
context
)
{
String
redisHosts
=
(
String
)
context
.
get
(
KEY_OF_REDIS_HOSTS
);
String
redisHosts
=
(
String
)
context
.
get
(
KEY_OF_REDIS_HOSTS
);
if
(!
StringUtil
.
isEmpty
(
redisHosts
))
{
span
.
setPeer
Host
(
context
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
));
span
.
setPeer
s
((
String
)
context
.
get
(
KEY_OF_REDIS_HOST
));
}
else
{
span
.
setPeerHost
(
context
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
));
span
.
setPort
(
context
.
get
(
KEY_OF_REDIS_PORT
,
Integer
.
class
));
span
.
setPeerHost
((
String
)
context
.
get
(
KEY_OF_REDIS_HOST
));
Integer
port
=
(
Integer
)
context
.
get
(
KEY_OF_REDIS_PORT
);
if
(
port
!=
null
)
{
span
.
setPort
(
port
);
}
}
}
@Override
public
Object
afterMethod
(
EnhancedClassInstanceContext
context
,
InstanceMethodInvokeContext
interceptorContext
,
Object
ret
)
{
Object
ret
)
{
this
.
whenExist
(
context
);
return
ret
;
}
@Override
public
void
handleMethodException
(
Throwable
t
,
EnhancedClassInstanceContext
context
,
InstanceMethodInvokeContext
interceptorContext
)
{
InstanceMethodInvokeContext
interceptorContext
)
{
ContextManager
.
activeSpan
().
log
(
t
);
}
...
...
@@ -81,11 +84,15 @@ public class JedisMethodInterceptor extends NoConcurrencyAccessObject implements
Tags
.
SPAN_KIND
.
set
(
span
,
Tags
.
SPAN_KIND_CLIENT
);
tagPeer
(
span
,
context
);
Tags
.
SPAN_LAYER
.
asDB
(
span
);
if
(
StringUtil
.
isEmpty
(
context
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
)))
{
span
.
setPeerHost
(
context
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
));
String
host
=
(
String
)
context
.
get
(
KEY_OF_REDIS_HOST
);
if
(
StringUtil
.
isEmpty
(
host
))
{
span
.
setPeers
((
String
)
context
.
get
(
KEY_OF_REDIS_HOSTS
));
}
else
{
span
.
setPeerHost
(
context
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
));
span
.
setPort
(
context
.
get
(
KEY_OF_REDIS_PORT
,
Integer
.
class
));
span
.
setPeerHost
(
host
);
Integer
port
=
(
Integer
)
context
.
get
(
KEY_OF_REDIS_PORT
);
if
(
port
!=
null
)
{
span
.
setPort
(
port
);
}
}
if
(
interceptorContext
.
allArguments
().
length
>
0
...
...
apm-sniffer/apm-sdk-plugin/jedis-2.x-plugin/src/test/java/org/skywalking/apm/plugin/jedis/v2/JedisMethodInterceptorTest.java
浏览文件 @
14f9154b
package
org.skywalking.apm.plugin.jedis.v2
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
org.hamcrest.CoreMatchers
;
import
org.hamcrest.MatcherAssert
;
import
org.junit.After
;
...
...
@@ -14,6 +16,8 @@ import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceCon
import
org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext
;
import
org.skywalking.apm.sniffer.mock.context.MockTracerContextListener
;
import
org.skywalking.apm.sniffer.mock.context.SegmentAssert
;
import
org.skywalking.apm.sniffer.mock.trace.tags.BooleanTagReader
;
import
org.skywalking.apm.sniffer.mock.trace.tags.StringTagReader
;
import
org.skywalking.apm.trace.LogData
;
import
org.skywalking.apm.trace.Span
;
import
org.skywalking.apm.trace.TraceSegment
;
...
...
@@ -45,7 +49,7 @@ public class JedisMethodInterceptorTest {
TracerContext
.
ListenerManager
.
add
(
mockTracerContextListener
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
)).
thenReturn
(
"127.0.0.1"
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_HOST
)).
thenReturn
(
"127.0.0.1"
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_PORT
)).
thenReturn
(
6379
);
when
(
methodInvokeContext
.
methodName
()).
thenReturn
(
"set"
);
when
(
methodInvokeContext
.
allArguments
()).
thenReturn
(
new
Object
[]
{
"OperationKey"
});
...
...
@@ -54,9 +58,9 @@ public class JedisMethodInterceptorTest {
@Test
public
void
testIntercept
()
{
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
0
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
0
);
interceptor
.
beforeMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
1
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
1
);
interceptor
.
afterMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
mockTracerContextListener
.
assertSize
(
1
);
...
...
@@ -72,12 +76,12 @@ public class JedisMethodInterceptorTest {
@Test
public
void
testInterceptWithMultiHost
()
{
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
0
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_HOST
,
String
.
class
)).
thenReturn
(
null
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
0
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_HOST
)).
thenReturn
(
null
);
when
(
classInstanceContext
.
get
(
KEY_OF_REDIS_HOSTS
)).
thenReturn
(
"127.0.0.1:6379;127.0.0.1:16379;"
);
interceptor
.
beforeMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
1
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
1
);
interceptor
.
afterMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
mockTracerContextListener
.
assertSize
(
1
);
...
...
@@ -93,10 +97,10 @@ public class JedisMethodInterceptorTest {
@Test
public
void
testInterceptWithException
()
{
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
0
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
0
);
interceptor
.
beforeMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
interceptor
.
handleMethodException
(
new
RuntimeException
(),
classInstanceContext
,
methodInvokeContext
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
,
Integer
.
class
)).
thenReturn
(
1
);
when
(
classInstanceContext
.
get
(
"__$invokeCounterKey"
)).
thenReturn
(
1
);
interceptor
.
afterMethod
(
classInstanceContext
,
methodInvokeContext
,
null
);
mockTracerContextListener
.
assertSize
(
1
);
...
...
@@ -106,8 +110,18 @@ public class JedisMethodInterceptorTest {
assertThat
(
traceSegment
.
getSpans
().
size
(),
is
(
1
));
Span
span
=
traceSegment
.
getSpans
().
get
(
0
);
assertRedisSpan
(
span
);
assertThat
(
span
.
getLogs
().
size
(),
is
(
1
));
assertLogData
(
span
.
getLogs
().
get
(
0
));
try
{
Field
logs
=
Span
.
class
.
getDeclaredField
(
"logs"
);
logs
.
setAccessible
(
true
);
List
<
LogData
>
logData
=
(
List
<
LogData
>)
logs
.
get
(
span
);
assertThat
(
logData
.
size
(),
is
(
1
));
assertLogData
(
logData
.
get
(
0
));
}
catch
(
NoSuchFieldException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
});
}
...
...
@@ -121,21 +135,21 @@ public class JedisMethodInterceptorTest {
private
void
assertRedisSpan
(
Span
span
)
{
assertThat
(
span
.
getOperationName
(),
is
(
"Jedis/set"
));
assertThat
(
Tags
.
PEER_HOST
.
get
(
span
),
is
(
"127.0.0.1"
));
assertThat
(
Tags
.
PEER_PORT
.
get
(
span
),
is
(
6379
));
assertThat
(
Tags
.
COMPONENT
.
get
(
span
),
is
(
"Redis"
));
assertThat
(
Tags
.
DB_STATEMENT
.
get
(
span
),
is
(
"set OperationKey"
));
assertThat
(
Tags
.
DB_TYPE
.
get
(
span
),
is
(
"Redis"
));
assertT
rue
(
Tags
.
SPAN_LAYER
.
isDB
(
span
));
assertThat
(
span
.
getPeerHost
(
),
is
(
"127.0.0.1"
));
assertThat
(
span
.
getPort
(
),
is
(
6379
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
COMPONENT
),
is
(
"Redis"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_STATEMENT
),
is
(
"set OperationKey"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_TYPE
),
is
(
"Redis"
));
assertT
hat
(
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
),
is
(
"db"
));
}
private
void
assertRedisSpan
(
Span
span
,
String
exceptedPeerHosts
)
{
assertThat
(
span
.
getOperationName
(),
is
(
"Jedis/set"
));
assertThat
(
Tags
.
PEERS
.
get
(
span
),
is
(
exceptedPeerHosts
));
assertThat
(
Tags
.
COMPONENT
.
get
(
span
),
is
(
"Redis"
));
assertThat
(
Tags
.
DB_STATEMENT
.
get
(
span
),
is
(
"set OperationKey"
));
assertThat
(
Tags
.
DB_TYPE
.
get
(
span
),
is
(
"Redis"
));
assertT
rue
(
Tags
.
SPAN_LAYER
.
isDB
(
span
));
assertThat
(
span
.
getPeers
(
),
is
(
exceptedPeerHosts
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
COMPONENT
),
is
(
"Redis"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_STATEMENT
),
is
(
"set OperationKey"
));
assertThat
(
StringTagReader
.
get
(
span
,
Tags
.
DB_TYPE
),
is
(
"Redis"
));
assertT
hat
(
StringTagReader
.
get
(
span
,
Tags
.
SPAN_LAYER
.
SPAN_LAYER_TAG
),
is
(
"db"
));
}
@After
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录