Finish cn documents

This commit is contained in:
wu-sheng 2017-11-06 16:37:22 +08:00
parent b7293702f6
commit d6a6fe10a0
13 changed files with 849 additions and 16 deletions

View File

@ -2,7 +2,7 @@
[![EN doc](https://img.shields.io/badge/document-English-blue.svg)](README.md)
* [项目简介](/README_ZH.md)
* [快速入门](cn/Quick-start-chn.md)
* [快速入门](cn/Quick-start-CN.md)
* [部署单机collector](cn/Deploy-collector-in-standalone-mode-CN.md)
* [部署集群collector](cn/Deploy-collector-in-cluster-mode-CN.md)
* [部署探针Agent](cn/Deploy-skywalking-agent-CN.md)
@ -12,24 +12,22 @@
* APM相关介绍资料
* [APM简介百度百科](http://baike.baidu.com/link?url=HizLjnUrwvXqPQ4fZH_MA81MA7R_sE-kpdEIfuUHf-yNHhPiEkA97_7FshVR6raiZL6pvbChTZSIgrC1lY6lhq.md)
* [OpenTracing中文版](https://github.com/opentracing-contrib/opentracing-specification-zh.md)
* [JVM内存管理与GC](cn/Memory-Usage-and-GC-info.md)
* Application Toolkit应用程序工具包
* [概述](cn/sky-walking-application-toolkit-chn.md)
* [OpenTracing Tracer](cn/skywalking-opentracing-chn.md)
* [概述](cn/Application-toolkit-CN.md)
* [OpenTracing Tracer](cn/skywalking-opentracing-CN.md)
* 日志组件
* [log4j组件](cn/sky-walking-application-toolkit-log4j-1.x-chn.md)
* [log4j2组件](cn/sky-walking-application-toolkit-log4j-2.x-chn.md)
* [logback组件](cn/sky-walking-application-toolkit-logback-1.x-chn.md)
* [Trace](cn/sky-walking-application-toolkit-trace-chn.md)
* [log4j组件](cn/Application-toolkit-log4j-1.x-CN.md)
* [log4j2组件](cn/Application-toolkit-log4j-2.x-CN.md)
* [logback组件](cn/Application-toolkit-logback-1.x-CN.md)
* [Trace](cn/Application-toolkit-trace-CN.md)
* 测试用例
* [单插件测试用例](cn/Test-Cases-chn.md)
* [测试应用集群](cn/2.0-Demo-Application-Cluster-chn.md)
* [插件测试](https://github.com/SkywalkingTest/agent-integration-test-report)
* [Java 探针性能测试](https://skywalkingtest.github.io/Agent-Benchmarks/)
* 开发指南
* [工程编译指南](cn/How-to-build.md)
* [插件开发指南](cn/Plugin-Development-Guide.md)
* [工程编译指南](cn/How-to-build-CN.md)
* [插件开发指南](cn/Plugin-Development-Guide-CN.md)
* [跨进程追踪上下文传递协议](cn/Skywalking-3-Cross-Process-Propagation-Headers-Protocol-CN.md)
* [探针与Collector间网络协议v3.2+](cn/How-to-communicate-with-the-collector%3F.md)
* [探针与Collector间网络协议v3.2+](cn/How-to-communicate-with-the-collector-CN.md)
* FAQ
* [探针性能测试报告](https://skywalkingtest.github.io/Agent-Benchmarks/.md)
* [Trace查询有数据但是没有拓扑图和JVM数据?](cn/Trace%E6%9F%A5%E8%AF%A2%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BD%86%E6%98%AF%E6%B2%A1%E6%9C%89%E6%8B%93%E6%89%91%E5%9B%BE%E5%92%8CJVM%E6%95%B0%E6%8D%AE.md)
* [加载探针Console被GRPC日志刷屏](cn/加载探针Console被GRPC日志刷屏.md)
* [Trace查询有数据但是没有拓扑图和JVM数据?](cn/FAQ/Why-have-traces-no-others-CN.md)
* [加载探针Console被GRPC日志刷屏](cn/FAQ/Too-many-gRPC-logs-CN.md)

View File

@ -0,0 +1,11 @@
# 什么是sky-walking应用程序工具包?
Sky-walking应用程序工具包是一系列的类库有skywalking团队提供。通过这些类库你可以在你的应用程序内访问sky-walking的一些内部信息.
_**最为重要的是**_, 即使你移除skywalking的探针或者不激活探针这些类库也不会对应用程序有任何影响也不会影响性能.
工具包提供以下核心能力
1. 将追踪信息和log组件集成如log4j, log4j2 和 logback
1. 兼容CNCF OpenTracing标准的手动埋点
1. 使用Skywalking专有的标注和交互性API
_**注意**: 所有的应用程序工具包都托管在bitray.com/jcenter. 同时请确保你使用的开发工具包和skywalking的agent探针版本一致._

View File

@ -0,0 +1,21 @@
* 使用 maven 和 gradle 依赖相应的工具包
```xml
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-log4j-1.x</artifactId>
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-1.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-1.x/_latestVersion)
* 配置layout
```properties
log4j.appender.CONSOLE.layout=org.skywalking.apm.toolkit.log.log4j.v1.x.TraceIdPatternLayout
```
* 在`layout.ConversionPattern`中设置 `%T`来展示traceid ( 在 2.0-2016版本中, 你应该设置为 %x, [为什么改变配置请参考相关issue?](https://github.com/wu-sheng/sky-walking/issues/77) )
```properties
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%T] %-5p %c{1}:%L - %m%n
```
* 当你使用`-javaagent`参数激活sky-walking的探针, 如果当前上下文中存在traceidlog4j将在输出**traceId**。如果探针没有被激活,将输出`TID: N/A`.

View File

@ -0,0 +1,19 @@
* 使用 maven 和 gradle 依赖相应的工具包
```xml
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-log4j-2.x</artifactId>
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-2.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-2.x/_latestVersion)
* 在log4j2.xml中的pattern 配置节,配置`[%traceId]`
```xml
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d [%traceId] %-5p %c{1}:%L - %m%n"/>
</Console>
</Appenders>
```
* 当你使用`-javaagent`参数激活sky-walking的探针, 如果当前上下文中存在traceidlog4j2将在输出**traceId**。如果探针没有被激活,将输出`TID: N/A`.

View File

@ -0,0 +1,22 @@
* 使用 maven 和 gradle 依赖相应的工具包
```xml
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-2.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.skywalking.apm-toolkit-log4j-2.x/_latestVersion)
* 在logback.xml中的`Pattern`配制节中,设置`%tid`
```xml
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
```
* 当你使用`-javaagent`参数激活sky-walking的探针, 如果当前上下文中存在traceidlogback将在输出**traceId**。如果探针没有被激活,将输出`TID: N/A`.

View File

@ -0,0 +1,20 @@
* 使用 maven 和 gradle 依赖相应的工具包
```xml
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>${skywalking.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.skywalking.apm-toolkit-trace/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.skywalking.apm-toolkit-trace/_latestVersion)
* 随时使用 `TraceContext.traceId()` API在应用程序的任何地方获取traceId.
```java
import org.skywalking.apm.toolkit.trace.TraceContext;
...
modelAndView.addObject("traceId", TraceContext.traceId());
```
_示例代码仅供参考_
* 对任何需要追踪的方法,使用@Trace标注则此方法会被加入到追踪链中。

View File

@ -0,0 +1,7 @@
**现象**
1. 加载探针并启动应用
2. Console中被GRPC日志刷屏
**原因**Skywalking采用了GRPC框架发送数据GRPC框架读取log的配置文件进行日志输出。
**解决方法**: 在log的配置文件中添加对`org.skywalking.apm.dependencies`包的过滤

View File

@ -0,0 +1,11 @@
现象:
- Agent和Collector正常工作没有异常日志
- 已经对系统进行过访问Trace查询有数据
- UI除Trace查询页面外其他页面无数据
- **页面顶部时间轴和当前系统时间不一致**
原因:
被监控系统所在的操作系统,未设置为当前时区,导致统计数据汇集时间点偏差。
解决方法:
设置操作系统时间时区

View File

@ -0,0 +1,18 @@
## 工程编译指南
本文档用于指导开发者,在本地开发环境中编译工程。
### 前言
因为工程结构和代码依赖会随版本变化如果读者熟悉travis-ci,则可直接参考[.travis.yml](https://github.com/wu-sheng/sky-walking/blob/master/.travis.yml)
### 编译步骤
1. 准备环境jdk8Maven
1. 执行`mvn clean package`
### 在IntelliJ IDEA中编译工程
上述步骤在命令行中,能够很好的编译工程,但导入到编译器中的工程依然会有一些报错,我们需要进行几步简单的操作。
1. 在IntelliJ Terminal中执行`mvn compile -Dmaven.test.skip=true`进行编译
1. 设置gRPC的自动生成代码目录为源码目录
- **apm-network/target/generated--sources/protobuf**目录下的`grpc-java`和`java`目录
- **apm-collector/apm-collector-stream/target/protobuf**目录下的`grpc-java`和`java`目录
从3.2开始网络通讯协议引入GRPC所以增加上述的步骤

View File

@ -0,0 +1,352 @@
# 探针与Collector间通讯协议
## 前言
这篇文章主要介绍3.2版本的Collector对外提供的服务协议。一般情况下使用者和开发者都无需了解此协议细节。但是在庞大的开源生态中我们已经收到过多次有公司或个人的使用案例使用自己的非Java探针PHP,GO等探针接入我们的Collector进行数据分析和监控。
## 协议类型
Collector从3.2开始对外同时提供gRPC和HTTP RESTFul两种类型的协议。从效率上我们推荐使用gRPC
# gRPC服务
本章节描述官方java探针使用的网络协议
## Collector服务发现协议
### 简介
**Collector服务发现协议是探针启动时第一个调用的服务。**通过服务查找对应的gRPC服务地址与端口列表并在由客户端选择其中任意一个作为服务端。此服务需周期性调用确保探针本地的服务端口列表是准确有效的。
### 协议类型
HTTP GET
### 协议内容
- 请求
GET操作http://collectorIp:port/agentstream/grpc 。 其中`/agentstream/grpc`是默认值如需修改需要参考collector相关配置。
- 返回
JSON数组数组的每个元素为一个有效的gRPC服务地址。
```json
["ip address1:port1","ip address2:port2","ip address3:port3"]
```
## 应用注册服务
### 简介
应用注册服务是将手动设计的applicationCode以及ip:port沟通的服务地址转换成数字的服务。此服务会在后续的传输过程中有效降低网络带宽需求。
### 协议类型
gRPC服务
### 协议内容
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/ApplicationRegisterService.proto
```proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.skywalking.apm.network.proto";
import "KeyWithIntegerValue.proto";
//register service for ApplicationCode, this service is called when service starts.
service ApplicationRegisterService {
rpc register (Application) returns (ApplicationMapping) {
}
}
message Application {
repeated string applicationCode = 1;
}
message ApplicationMapping {
repeated KeyWithIntegerValue application = 1;
}
```
- 首次调用时applicationCode为客户端设置的应用名显示在拓扑图和应用列表上的名字。之后随着追踪过程会上报此应用相关的周边服务的`ip:port`地址列表
- KeyWithIntegerValue 返回key为上报的applicationCode和ip:port地址value为对应的id。applicationCode对应的返回id,在后续协议中被称为applicationId。
- 此服务按需调用本地无法找到ip:port对应的id时可异步发起调用。
- 获取applicationId的操作是必选。
- 获取ip:port对应的id是可选但是完成id设置会有效提高collector处理效率降低网络消耗。
## 应用实例发现服务
### 简介
应用实例发现服务存在三个子服务,分别是实例注册服务,实例心跳服务,实例注册重连服务。这三个服务负责获取和保持应用实例在线的功能。
### 协议类型
gRPC服务
### 实例注册服务
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L11-L12
```proto
service InstanceDiscoveryService {
rpc register (ApplicationInstance) returns (ApplicationInstanceMapping) {
}
}
message ApplicationInstance {
int32 applicationId = 1;
string agentUUID = 2;
int64 registerTime = 3;
OSInfo osinfo = 4;
}
message OSInfo {
string osName = 1;
string hostname = 2;
int32 processNo = 3;
repeated string ipv4s = 4;
}
message ApplicationInstanceMapping {
int32 applicationId = 1;
int32 applicationInstanceId = 2;
}
```
- agentUUID 由探针生成需保持唯一性推荐使用UUID算法。并在应用重启前保持不变
- applicationId 由**应用注册服务**获取。
- 服务端返回应用实例idapplicationInstanceId 。后续上报服务使用实例id标识。
### 实例心跳服务
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L14-L15
```proto
service InstanceDiscoveryService {
rpc heartbeat (ApplicationInstanceHeartbeat) returns (Downstream) {
}
}
message ApplicationInstanceHeartbeat {
int32 applicationInstanceId = 1;
int64 heartbeatTime = 2;
}
```
- 心跳服务每分钟上报一次。
- 如一分钟内有segment数据上报则可不必上报心跳。
### 实例注册重连服务
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L17-L18
```proto
service InstanceDiscoveryService {
rpc registerRecover (ApplicationInstanceRecover) returns (Downstream) {
}
}
message ApplicationInstanceRecover {
int32 applicationId = 1;
int32 applicationInstanceId = 2;
int64 registerTime = 3;
OSInfo osinfo = 4;
}
```
- 应用重连服务于**应用注册服务**类似在gRPC发生重连并再次连接成功后发送。需包含通过**应用注册服务**获取的applicationInstanceId。
## 服务名注册发现服务
### 简介
服务名注册发现服务是将应用内的服务名operationName替换为id的服务。
### 协议类型
gRPC服务
### 协议内容
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L53-L74
```proto
//discovery service for ServiceName by Network address or application code
service ServiceNameDiscoveryService {
rpc discovery (ServiceNameCollection) returns (ServiceNameMappingCollection) {
}
}
message ServiceNameCollection {
repeated ServiceNameElement elements = 1;
}
message ServiceNameMappingCollection {
repeated ServiceNameMappingElement elements = 1;
}
message ServiceNameMappingElement {
int32 serviceId = 1;
ServiceNameElement element = 2;
}
message ServiceNameElement {
string serviceName = 1;
int32 applicationId = 2;
}
```
- 可选服务可有效降低网络消耗推荐实现。注意由于部分应用存在URI中夹带参数的情况请注意限制探针内的缓存容量防止内存溢出。
- ServiceNameElement中applicationId为当前applicationCode对应的id。serviceName一般为对应span的operationName
## JVM指标上报服务
### 简介
上报当前实例的JVM信息每秒上报一次。
### 协议类型
gRPC服务
### 协议内容
https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/proto/JVMMetricsService.proto
```proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.skywalking.apm.network.proto";
import "Downstream.proto";
service JVMMetricsService {
rpc collect (JVMMetrics) returns (Downstream) {
}
}
message JVMMetrics {
repeated JVMMetric metrics = 1;
int64 applicationInstanceId = 2;
}
message JVMMetric {
int64 time = 1;
CPU cpu = 2;
repeated Memory memory = 3;
repeated MemoryPool memoryPool = 4;
repeated GC gc = 5;
}
message CPU {
double usagePercent = 2;
}
message Memory {
bool isHeap = 1;
int64 init = 2;
int64 max = 3;
int64 used = 4;
int64 committed = 5;
}
message MemoryPool {
PoolType type = 1;
bool isHeap = 2;
int64 init = 3;
int64 max = 4;
int64 used = 5;
int64 commited = 6;
}
enum PoolType {
CODE_CACHE_USAGE = 0;
NEWGEN_USAGE = 1;
OLDGEN_USAGE = 2;
SURVIVOR_USAGE = 3;
PERMGEN_USAGE = 4;
METASPACE_USAGE = 5;
}
message GC {
GCPhrase phrase = 1;
int64 count = 2;
int64 time = 3;
}
enum GCPhrase {
NEW = 0;
OLD = 1;
}
```
## TraceSegment上报服务
### 简介
上报调用链信息
### 协议类型
gRPC服务
### 协议内容
```proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.skywalking.apm.network.proto";
import "Downstream.proto";
import "KeyWithStringValue.proto";
service TraceSegmentService {
rpc collect (stream UpstreamSegment) returns (Downstream) {
}
}
message UpstreamSegment {
repeated UniqueId globalTraceIds = 1;
bytes segment = 2; // the byte array of TraceSegmentObject
}
message UniqueId {
repeated int64 idParts = 1;
}
message TraceSegmentObject {
UniqueId traceSegmentId = 1;
repeated TraceSegmentReference refs = 2;
repeated SpanObject spans = 3;
int32 applicationId = 4;
int32 applicationInstanceId = 5;
}
message TraceSegmentReference {
RefType refType = 1;
UniqueId parentTraceSegmentId = 2;
int32 parentSpanId = 3;
int32 parentApplicationInstanceId = 4;
string networkAddress = 5;
int32 networkAddressId = 6;
string entryServiceName = 7;
int32 entryServiceId = 8;
string parentServiceName = 9;
int32 parentServiceId = 10;
}
message SpanObject {
int32 spanId = 1;
int32 parentSpanId = 2;
int64 startTime = 3;
int64 endTime = 4;
int32 operationNameId = 5;
string operationName = 6;
int32 peerId = 7;
string peer = 8;
SpanType spanType = 9;
SpanLayer spanLayer = 10;
int32 componentId = 11;
string component = 12;
bool isError = 13;
repeated KeyWithStringValue tags = 14;
repeated LogMessage logs = 15;
}
enum RefType {
CrossProcess = 0;
CrossThread = 1;
}
enum SpanType {
Entry = 0;
Exit = 1;
Local = 2;
}
enum SpanLayer {
Database = 0;
RPCFramework = 1;
Http = 2;
MQ = 3;
}
message LogMessage {
int64 time = 1;
repeated KeyWithStringValue data = 2;
}
```
- UniqueId为segment或者globalTraceId的数字表示。由3个long组成1applicationInstanceId2当前线程id3当前时间戳*10000 + seq(0-10000自循环)
- Span的数据请参考[插件开发规范](https://github.com/OpenSkywalking/skywalking/wiki/Plugin-Development-Guide)
- 以下id和名称根据注册返回结果优先上报id无法获取id时再上传name。参考之前的应用和服务注册章节。
- operationNameId/operationName
- networkAddress/networkAddressId
- entryServiceName/entryServiceId
- parentServiceName/parentServiceId
- peerId/peer
- componentId为默认支持的插件id非官方支持需传输名称或修改服务端源代码。[官方组件列表](https://github.com/OpenSkywalking/skywalking/blob/master/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java)

View File

@ -0,0 +1,276 @@
## 插件开发指南
本文档描述 [v3.2+](https://github.com/OpenTracing/skywalking/releases) 插件开发方法、使用的API以及注意事项。3.2版本将在2017 CNUTCon之前发布。
### 核心概念
#### 一. Span
Span是追踪系统中的通用概念有时候被翻译成埋点关于Span的定义请参考[OpenTracing 中文版](https://github.com/opentracing-contrib/opentracing-specification-zh/blob/master/specification.md#opentracing数据模型)。
sky-walking作为OpenTracing的支持者在核心实现中与标准有较高的相似度。
我们将span分为三类
1.1 EntrySpan
EntrySpan代表一个服务的提供方服务端的入口点。它是每个Java对外服务的入口点。如Web服务入口就是一个EntrySpan。
1.2 LocalSpan
LocalSpan代表一个普通的Span,代表任意一个本地逻辑块(或方法)
1.3 ExitSpan
ExitSpan也可以称为LeafSpan(sky-walking的早期版本中的称呼)代表了一个远程服务的客户端调用。如一次JDBC调用。
#### 二. ContextCarrier
分布式追踪要解决的一个重要问题就是跨进程的问题ContextCarrier的概念就是为了解决这种场景。
当发生一次**A->B**的网络调用时:
1. 需要在客户端生成(inject操作)ContextCarrier并序列化成String
1. 将这个String加入RPC调用的正文或HEAD传递到服务端
1. 服务端收到后转换为新的ContextCarrier
1. 通过提取操作extract操作建立关联
以HTTPComponent调用Tomcat为例
1. 客户端HTTPComponent端
```java
span = ContextManager.createExitSpan("/span/operation/name", contextCarrier, "ip:port");
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
//向HTTP或者其他RPC HEAD中设置上下文
heads.put(next.getHeadKey(), next.getHeadValue());
}
```
2. 服务端Tomcat端
```java
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
//从HTTP或者其他RPC HEAD中根据指定的KEY提取上下文
next.setHeadValue(heads.get(next.getHeadKey()));
}
span = ContextManager.createEntrySpan(“/span/operation/name”, contextCarrier);
```
#### 三. ContextSnapshot
除了跨进程的RPC调用另外一种追踪的常见场景是跨线程。跨线程和跨进程有很高的相似度都是需要完成上下文的传递工作。所以ContextSnapshot具有和ContextCarrier十分类似的API风格。
当发生一次**A->B**的跨线程调用时:
1. 需要在A线程中通过ContextManager#capture操作生成ContextSnapshot对象实例
1. 将这个ContextSnapshot对象传递到B线程中
1. B线程通过ContextManager#continued操作完成上下文传递
### 核心API
#### 一. ContextManager
ContextManager提供了追踪相关操作的主入口
1. 创建EntrySpan
```java
public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier)
```
通过服务名、跨进程传递的ContextCarrier创建EntrySpan。
2. 创建LocalSpan
```java
public static AbstractSpan createLocalSpan(String operationName)
```
根据服务名或方法名创建LocalSpan
3. 创建ExitSpan
```java
public static AbstractSpan createExitSpan(String operationName, ContextCarrier carrier, String remotePeer)
```
根据服务名跨进程传递的ContextCarrier空容器和远端服务地址IP、主机名、域名 + 端口创建ExitSpan
#### 二. AbstractSpan
AbstractSpan提供了Span内部进行操作的各项API
```java
/**
* Set the component id, which defines in {@link org.skywalking.apm.network.trace.component.ComponentsDefine}
*
* @param component
* @return the span for chaining.
*/
AbstractSpan setComponent(Component component);
/**
* Only use this method in explicit instrumentation, like opentracing-skywalking-bridge.
* It it higher recommend don't use this for performance consideration.
*
* @param componentName
* @return the span for chaining.
*/
AbstractSpan setComponent(String componentName);
AbstractSpan setLayer(SpanLayer layer);
/**
* Set a key:value tag on the Span.
*
* @return this Span instance, for chaining
*/
AbstractSpan tag(String key, String value);
/**
* Record an exception event of the current walltime timestamp.
*
* @param t any subclass of {@link Throwable}, which occurs in this span.
* @return the Span, for chaining
*/
AbstractSpan log(Throwable t);
AbstractSpan errorOccurred();
/**
* Record an event at a specific timestamp.
*
* @param timestamp The explicit timestamp for the log record.
* @param event the events
* @return the Span, for chaining
*/
AbstractSpan log(long timestamp, Map<String, ?> event);
/**
* Sets the string name for the logical operation this span represents.
*
* @return this Span instance, for chaining
*/
AbstractSpan setOperationName(String operationName);
```
Span的操作语义和OpenTracing类似。
SpanLayer为我们的特有概念如果是远程调用类的服务请设置此属性包括4个属性值
1. DB
1. RPC_FRAMEWORK非HTTP类型的RPC框架原生的DUBBOMOTAN
1. HTTP
1. MQ
### 开发插件
#### 一. 简介
因为所有的程序调用都是基于方法的所以插件实际上就是基于方法的拦截类似面向切面编程的AOP技术。sky-walking底层已经完成相关的技术封装所以插件开发者只需要定位需要拦截的类、方法然后结合上文中的追踪API即可完成插件的开发。
#### 二. 拦截类型
根据Java方法共有三种拦截类型
1. 拦截构造函数
1. 拦截实例方法
1. 拦截静态方法
我们将这三类拦截,分为两类,即:
1. 实例方法增强插件继承ClassInstanceMethodsEnhancePluginDefine
1. 静态方法增强插件继承ClassStaticMethodsEnhancePluginDefine
当然也可以同时支持实例和静态方法直接继承ClassEnhancePluginDefine。但是这种情况很少。
#### 三. 实现自己的插件定义
我们以继承ClassInstanceMethodsEnhancePluginDefine为例ClassStaticMethodsEnhancePluginDefine十分类似不再重复描述描述定义插件的全过程
1. 定义目标类名称
```java
protected abstract ClassMatch enhanceClass();
```
ClassMatch反应类的匹配方式目前提供三种
* byName, 通过类名完整匹配
* byClassAnnotationMatch, 通过类标注进行匹配
* byMethodAnnotationMatch, 通过方法的标注来匹配类
* byHierarchyMatch, 通过父类或者接口匹配
注意实现:
* 所有类、接口、标注名称,请使用字符串,不要使用`*.class.getName()`(用户环境可能会引起ClassLoader问题)。
* by*AnnotationMatch不支持继承的标注
* byHierarchyMatch如果存在接口、抽象类、类间的多层继承关系如果方法复写则可能造成多层埋点。
如:
```java
@Override
protected ClassMatch enhanceClassName() {
return byName("org.apache.catalina.core.StandardEngineValve");
}
```
2. 定义构造函数拦截点
```java
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints();
public interface InstanceMethodsInterceptPoint {
/**
* class instance methods matcher.
*
* @return methods matcher
*/
ElementMatcher<MethodDescription> getMethodsMatcher();
/**
* @return represents a class name, the class instance must instanceof InstanceMethodsAroundInterceptor.
*/
String getMethodsInterceptor();
boolean isOverrideArgs();
}
```
返回拦截方法的匹配器以及对应的拦截类同样由于潜在的ClassLoader问题不要使用`*.class.getName()`。如何构建拦截器,请章节"四. 实现拦截器逻辑"。
3. 定义skywalking-plugin.def文件
```properties
tomcat-7.x/8.x=org.skywalking.apm.plugin.tomcat78x.define.TomcatInstrumentation
```
* 插件名称,要求全局唯一,命名规范:目标组件+版本号
* 插件定义类全名
#### 四. 实现拦截器逻辑
我们继续以实现实例方法拦截为例拦截器需要实现org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor。
```java
/**
* A interceptor, which intercept method's invocation. The target methods will be defined in {@link
* ClassEnhancePluginDefine}'s subclass, most likely in {@link ClassInstanceMethodsEnhancePluginDefine}
*
* @author wusheng
*/
public interface InstanceMethodsAroundInterceptor {
/**
* called before target method invocation.
*
* @param result change this result, if you want to truncate the method.
* @throws Throwable
*/
void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable;
/**
* called after target method invocation. Even method's invocation triggers an exception.
*
* @param ret the method's original return value.
* @return the method's actual return value.
* @throws Throwable
*/
Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable;
/**
* called when occur exception.
*
* @param t the exception occur.
*/
void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Throwable t);
}
```
可以在方法执行前、执行后、执行异常三个点进行拦截设置修改方法参数执行前并调用核心API设置追踪逻辑。
### 贡献插件到主仓库
我们鼓励大家共同贡献支持各个类库的插件。
大家需支持以下步骤执行:
1. 在issue页面提出插件扩展需求对应的版本。
1. Fork wu-sheng/sky-walking到本地
1. 在apm-sniffer/apm-sdk-plugin下新建自己的插件模块模块名为支持类库名称+版本号
1. 按照规范开发插件
1. 完善注释和测试用例
1. 在本地打包进行集成测试
1. 提交Pull Request到 wu-sheng/sky-walking提供插件追踪的截图拓扑和Trace明细可独立运行的被追踪程序、docker镜像或docker-compose。
1. sky-walking PMC( Project Management Committee) 成员完成插件审核,确定发布版本,并合并到主仓库。

View File

@ -0,0 +1,61 @@
# Skywalking 3 Cross Process Propagation Headers Protocol
* Version 1.0
这是Skywalking3跨进程传输头协议第一个公开版本。Skywalking是一个偏向APM的分布式追踪系统所以为了提供服务端处理性能。头信息会比其他的追踪系统要更复杂一些。你会发现这个头信息更像一个商业APM系统并且一些商业APM系统的头信息比我们的要复杂的多。所以如果你希望开发或者贡献其他语言探针、或者JAVA探针的其他市县模式请耐心阅读并理解此协议内容。
# Header Item
* Header Name: `sw3`
* Header Value: 使用`|`分隔,包含以下内容
## Values
* Trace Segment Id
Trace segment即分布式调用链片段。这个ID为此调用链片段全局唯一ID。此ID由一次分布式调用链的一个线程执行过程独享在Java模型中。ID由三个Long型组成 `"1.2343.234234234`
1) 第一部分代表应用的实例ID(`application instance id`)此ID通过注册接口由Collector分配。一般取值范围为整形利于protobuf传输。
2) 第二部分为线程号Java模型中一般也是整形。
3) 第三部分又由两部分组成
1) 时间戳,单位毫秒
2) 线程内的自增序列。0到9999之间。
如果你使用其他语言实现探针你只需要保证你的ID由三个Long型构成并全局唯一不必完全遵守Java的ID生成规则。
* Span Id
一个整数在trace segment内唯一从0开始自增。
* Parent Application Instance
父级应用节点的应用实例ID。如在一个RPC调用中HEAD中是客户端的应用实例ID。
* Entry Application Instance
入口应用节点的应用实例ID。如在一个分布式链路`A->B->C`中,此字段为`A`应用的实例ID。
* Peer Host
服务端的Peer Host或Peer Id。如客户端使用`182.14.39.1:9080`服务端则这个就是对应的Peer Host。
_此值可以通过Collector服务获得对应的ID。如果非ID则使用`#`开头如果使用ID则为整数类型。_
* Entry Span Operation Name of First Trace Segment
调用链入口节点的应用实例下,入口Span的operation name或id。
_此值可以通过Collector服务获得对应的ID。如果非ID则使用`#`开头如果使用ID则为整数类型。_
* Entry Span Operation Name of Parent Trace Segment
调用链父级节点的应用实例下,入口Span的operation name或id。
_此值可以通过Collector服务获得对应的ID。如果非ID则使用`#`开头如果使用ID则为整数类型。_
* Distributed Trace Id
分布式链路ID一般是整个调用链的全局唯一ID。如果针对批量消费情况这个ID是批量中第一个生产者的trace ID。此ID生成规则和`Trace Segment Id`一致由三个Long型数字构成。
### Sample value
value值示例
1. `1.2343.234234234|1|1|1|#127.0.0.1:8080|#/portal/|#/testEntrySpan|1.2343.234234234`
1. `1.2343.234234234|1|1|1|#127.0.0.1:8080|#/portal/|1038|1.2343.234234234`

View File

@ -0,0 +1,17 @@
* 使用 maven 和 gradle 依赖相应的工具包
```xml
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-toolkit-opentracing</artifactId>
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.skywalking.apm-toolkit-opentracing/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.skywalking.apm-toolkit-opentracing/_latestVersion)
* 使用OpenTracing的标准API和桥接器使用手动埋点
```java
Tracer tracer = new org.skywalking.apm.toolkit.opentracing.SkyWalkingTracer();
Tracer.SpanBuilder spanBuilder = tracer.buildSpan("/yourApplication/yourService");
```