You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2020/05/27 09:55:55 UTC
[incubator-apisix] branch master updated: feature: add skywalking
plugin. (#1241)
This is an automated email from the ASF dual-hosted git repository.
wenming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 398941b feature: add skywalking plugin. (#1241)
398941b is described below
commit 398941b72f0e35c671b7046f5dae2af97dbf9c74
Author: Wen Ming <mo...@gmail.com>
AuthorDate: Wed May 27 17:55:47 2020 +0800
feature: add skywalking plugin. (#1241)
---
Makefile | 3 +
README.md | 2 +-
README_CN.md | 2 +-
apisix/admin/routes.lua | 12 +-
apisix/plugins/skywalking.lua | 80 ++++++++++++
apisix/plugins/skywalking/client.lua | 226 ++++++++++++++++++++++++++++++++
apisix/plugins/skywalking/tracer.lua | 101 +++++++++++++++
apisix/plugins/zipkin.lua | 2 +-
bin/apisix | 1 +
conf/config.yaml | 2 +
doc/plugin-develop-cn.md | 6 +
doc/plugin-develop.md | 6 +
rockspec/apisix-master-0.rockspec | 1 +
t/APISIX.pm | 1 +
t/admin/plugins.t | 2 +-
t/debug/debug-mode.t | 1 +
t/lib/server.lua | 19 ++-
t/plugin/skywalking.t | 242 +++++++++++++++++++++++++++++++++++
18 files changed, 698 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
index 16ded88..760c692 100644
--- a/Makefile
+++ b/Makefile
@@ -151,6 +151,9 @@ install: default
$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/zipkin
$(INSTALL) apisix/plugins/zipkin/*.lua $(INST_LUADIR)/apisix/plugins/zipkin/
+ $(INSTALL) -d $(INST_LUADIR)/apisix/plugins/skywalking
+ $(INSTALL) apisix/plugins/skywalking/*.lua $(INST_LUADIR)/apisix/plugins/skywalking/
+
$(INSTALL) -d $(INST_LUADIR)/apisix/stream/plugins
$(INSTALL) apisix/stream/plugins/*.lua $(INST_LUADIR)/apisix/stream/plugins/
diff --git a/README.md b/README.md
index 73a4ee2..f6b4a4f 100644
--- a/README.md
+++ b/README.md
@@ -94,7 +94,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against
- [CORS](doc/plugins/cors.md)
- **OPS friendly**
- - OpenTracing: [support Apache Skywalking and Zipkin](doc/plugins/zipkin.md)
+ - OpenTracing: support [Apache Skywalking](doc/plugins/skywalking.md) and [Zipkin](doc/plugins/zipkin.md)
- Monitoring And Metrics: [Prometheus](doc/plugins/prometheus.md)
- Clustering: APISIX nodes are stateless, creates clustering of the configuration center, please refer to [etcd Clustering Guide](https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/clustering.md).
- High availability: support to configure multiple etcd addresses in the same cluster.
diff --git a/README_CN.md b/README_CN.md
index 2b85609..b914326 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -94,7 +94,7 @@ A/B 测试、金丝雀发布(灰度发布)、蓝绿部署、限流限速、抵
- [CORS](doc/plugins/cors-cn.md)
- **运维友好**
- - OpenTracing 可观测性: [支持 Apache Skywalking 和 Zipkin](doc/plugins/zipkin-cn.md)。
+ - OpenTracing 可观测性: 支持 [Apache Skywalking](doc/plugins/skywalking-cn.md) 和 [Zipkin](doc/plugins/zipkin-cn.md)。
- 监控和指标: [Prometheus](doc/plugins/prometheus-cn.md)
- 集群:APISIX 节点是无状态的,创建配置中心集群请参考 [etcd Clustering Guide](https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/clustering.md)。
- 高可用:支持配置同一个集群内的多个 etcd 地址。
diff --git a/apisix/admin/routes.lua b/apisix/admin/routes.lua
index 3303e8d..bb7092f 100644
--- a/apisix/admin/routes.lua
+++ b/apisix/admin/routes.lua
@@ -135,7 +135,7 @@ function _M.put(id, conf, sub_path, args)
local key = "/routes/" .. id
local res, err = core.etcd.set(key, conf, args.ttl)
if not res then
- core.log.error("failed to put route[", key, "]: ", err)
+ core.log.error("failed to put route[", key, "] to etcd: ", err)
return 500, {error_msg = err}
end
@@ -151,7 +151,7 @@ function _M.get(id)
local res, err = core.etcd.get(key)
if not res then
- core.log.error("failed to get route[", key, "]: ", err)
+ core.log.error("failed to get route[", key, "] from etcd: ", err)
return 500, {error_msg = err}
end
@@ -169,7 +169,7 @@ function _M.post(id, conf, sub_path, args)
-- core.log.info("key: ", key)
local res, err = core.etcd.push("/routes", conf, args.ttl)
if not res then
- core.log.error("failed to post route[", key, "]: ", err)
+ core.log.error("failed to post route[", key, "] to etcd: ", err)
return 500, {error_msg = err}
end
@@ -186,7 +186,7 @@ function _M.delete(id)
-- core.log.info("key: ", key)
local res, err = core.etcd.delete(key)
if not res then
- core.log.error("failed to delete route[", key, "]: ", err)
+ core.log.error("failed to delete route[", key, "] in etcd: ", err)
return 500, {error_msg = err}
end
@@ -214,7 +214,7 @@ function _M.patch(id, conf, sub_path, args)
local res_old, err = core.etcd.get(key)
if not res_old then
- core.log.error("failed to get route [", key, "]: ", err)
+ core.log.error("failed to get route [", key, "] in etcd: ", err)
return 500, {error_msg = err}
end
@@ -261,7 +261,7 @@ function _M.patch(id, conf, sub_path, args)
-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, node_value, args.ttl)
if not res then
- core.log.error("failed to set new route[", key, "]: ", err)
+ core.log.error("failed to set new route[", key, "] to etcd: ", err)
return 500, {error_msg = err}
end
diff --git a/apisix/plugins/skywalking.lua b/apisix/plugins/skywalking.lua
new file mode 100644
index 0000000..f95286b
--- /dev/null
+++ b/apisix/plugins/skywalking.lua
@@ -0,0 +1,80 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You 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.
+--
+local core = require("apisix.core")
+local ngx = ngx
+local math = math
+
+local sw_client = require("apisix.plugins.skywalking.client")
+local sw_tracer = require("apisix.plugins.skywalking.tracer")
+
+local plugin_name = "skywalking"
+
+
+local schema = {
+ type = "object",
+ properties = {
+ endpoint = {type = "string"},
+ sample_ratio = {type = "number", minimum = 0.00001, maximum = 1, default = 1}
+ },
+ service_name = {
+ type = "string",
+ description = "service name for skywalking",
+ default = "APISIX",
+ },
+ required = {"endpoint"}
+}
+
+
+local _M = {
+ version = 0.1,
+ priority = -1100, -- last running plugin, but before serverless post func
+ name = plugin_name,
+ schema = schema,
+}
+
+
+function _M.check_schema(conf)
+ return core.schema.check(schema, conf)
+end
+
+
+function _M.rewrite(conf, ctx)
+ core.log.debug("rewrite phase of skywalking plugin")
+ ctx.skywalking_sample = false
+ if conf.sample_ratio == 1 or math.random() < conf.sample_ratio then
+ ctx.skywalking_sample = true
+ sw_client.heartbeat(conf)
+ -- Currently, we can not have the upstream real network address
+ sw_tracer.start(ctx, conf.endpoint, "upstream service")
+ end
+end
+
+
+function _M.body_filter(conf, ctx)
+ if ctx.skywalking_sample and ngx.arg[2] then
+ sw_tracer.finish(ctx)
+ end
+end
+
+
+function _M.log(conf, ctx)
+ if ctx.skywalking_sample then
+ sw_tracer.prepareForReport(ctx, conf.endpoint)
+ end
+end
+
+return _M
diff --git a/apisix/plugins/skywalking/client.lua b/apisix/plugins/skywalking/client.lua
new file mode 100644
index 0000000..676735c
--- /dev/null
+++ b/apisix/plugins/skywalking/client.lua
@@ -0,0 +1,226 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You 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.
+--
+local core = require("apisix.core")
+local http = require("resty.http")
+local cjson = require('cjson')
+local ngx = ngx
+local ipairs = ipairs
+
+local register = require("skywalking.register")
+
+local _M = {}
+
+local function register_service(conf)
+ local endpoint = conf.endpoint
+
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local service_id = tracing_buffer:get(endpoint .. '_service_id')
+ if service_id then
+ return service_id
+ end
+
+ local service_name = conf.service_name
+ local service = register.newServiceRegister(service_name)
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri(endpoint .. '/v2/service/register',
+ {
+ method = "POST",
+ body = core.json.encode(service),
+ headers = {
+ ["Content-Type"] = "application/json",
+ },
+ })
+ if not res then
+ core.log.error("skywalking service register failed, request uri: ",
+ endpoint .. '/v2/service/register', ", err: ", err)
+
+ elseif res.status == 200 then
+ core.log.debug("skywalking service register response: ", res.body)
+ local register_results = cjson.decode(res.body)
+
+ for _, result in ipairs(register_results) do
+ if result.key == service_name then
+ service_id = result.value
+ core.log.debug("skywalking service registered, service id:"
+ .. service_id)
+ end
+ end
+
+ else
+ core.log.error("skywalking service register failed, request uri:",
+ endpoint .. "/v2/service/register",
+ ", response code:", res.status)
+ end
+
+ if service_id then
+ tracing_buffer:set(endpoint .. '_service_id', service_id)
+ end
+
+ return service_id
+end
+
+local function register_service_instance(conf, service_id)
+ local endpoint = conf.endpoint
+
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local instance_id = tracing_buffer:get(endpoint .. '_instance_id')
+ if instance_id then
+ return instance_id
+ end
+
+ local service_instance_name = core.id.get()
+ local service_instance = register.newServiceInstanceRegister(
+ service_id,
+ service_instance_name,
+ ngx.now() * 1000)
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri(endpoint .. '/v2/instance/register',
+ {
+ method = "POST",
+ body = core.json.encode(service_instance),
+ headers = {
+ ["Content-Type"] = "application/json",
+ },
+ })
+
+ if not res then
+ core.log.error("skywalking service Instance register failed",
+ ", request uri: ", conf.endpoint .. '/v2/instance/register',
+ ", err: ", err)
+
+ elseif res.status == 200 then
+ core.log.debug("skywalking service instance register response: ", res.body)
+ local register_results = cjson.decode(res.body)
+
+ for _, result in ipairs(register_results) do
+ if result.key == service_instance_name then
+ instance_id = result.value
+ core.log.debug("skywalking service Instance registered, ",
+ "service instance id: ", instance_id)
+ end
+ end
+
+ else
+ core.log.error("skywalking service instance register failed, ",
+ "response code:", res.status)
+ end
+
+ if instance_id then
+ tracing_buffer:set(endpoint .. '_instance_id', instance_id)
+ end
+
+ return instance_id
+end
+
+local function ping(endpoint)
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local ping_pkg = register.newServiceInstancePingPkg(
+ tracing_buffer:get(endpoint .. '_instance_id'),
+ core.id.get(),
+ ngx.now() * 1000)
+
+ local httpc = http.new()
+ local _, err = httpc:request_uri(endpoint .. '/v2/instance/heartbeat', {
+ method = "POST",
+ body = core.json.encode(ping_pkg),
+ headers = {
+ ["Content-Type"] = "application/json",
+ },
+ })
+
+ if err then
+ core.log.error("skywalking agent ping failed, err: ", err)
+ end
+end
+
+-- report trace segments to the backend
+local function report_traces(endpoint)
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local segment = tracing_buffer:rpop(endpoint .. '_segment')
+
+ local count = 0
+
+ local httpc = http.new()
+
+ while segment ~= nil do
+ local res, err = httpc:request_uri(endpoint .. '/v2/segments', {
+ method = "POST",
+ body = segment,
+ headers = {
+ ["Content-Type"] = "application/json",
+ },
+ })
+
+ if err == nil then
+ if res.status ~= 200 then
+ core.log.error("skywalking segment report failed, response code ", res.status)
+ break
+ else
+ count = count + 1
+ end
+ else
+ core.log.error("skywalking segment report failed, err: ", err)
+ break
+ end
+
+ segment = tracing_buffer:rpop('segment')
+ end
+
+ if count > 0 then
+ core.log.debug(count, " skywalking segments reported")
+ end
+end
+
+do
+ local heartbeat_timer
+
+function _M.heartbeat(conf)
+ local sw_heartbeat = function()
+ local service_id = register_service(conf)
+ if not service_id then
+ return
+ end
+
+ local service_instance_id = register_service_instance(conf, service_id)
+ if not service_instance_id then
+ return
+ end
+
+ report_traces(conf.endpoint)
+ ping(conf.endpoint)
+ end
+
+ local err
+ if ngx.worker.id() == 0 and not heartbeat_timer then
+ heartbeat_timer, err = core.timer.new("skywalking_heartbeat",
+ sw_heartbeat,
+ {check_interval = 3}
+ )
+ if not heartbeat_timer then
+ core.log.error("failed to create skywalking_heartbeat timer: ", err)
+ else
+ core.log.info("succeed to create timer: skywalking heartbeat")
+ end
+ end
+end
+
+end -- do
+
+
+return _M
diff --git a/apisix/plugins/skywalking/tracer.lua b/apisix/plugins/skywalking/tracer.lua
new file mode 100644
index 0000000..edc4bfe
--- /dev/null
+++ b/apisix/plugins/skywalking/tracer.lua
@@ -0,0 +1,101 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You 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.
+--
+local core = require("apisix.core")
+local span = require("skywalking.span")
+local tracing_context = require("skywalking.tracing_context")
+local span_layer = require("skywalking.span_layer")
+local sw_segment = require('skywalking.segment')
+
+local pairs = pairs
+local ngx = ngx
+
+-- Constant pre-defined in SkyWalking main repo
+-- 84 represents Nginx
+local NGINX_COMPONENT_ID = 6000
+
+local _M = {}
+
+function _M.start(ctx, endpoint, upstream_name)
+ local context
+ -- TODO: use lrucache for better performance
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local instance_id = tracing_buffer:get(endpoint .. '_instance_id')
+ local service_id = tracing_buffer:get(endpoint .. '_service_id')
+
+ if service_id and service_id then
+ context = tracing_context.new(service_id, instance_id)
+ else
+ context = tracing_context.newNoOP()
+ end
+
+ local context_carrier = {}
+ context_carrier["sw6"] = ngx.req.get_headers()["sw6"]
+ local entry_span = tracing_context.createEntrySpan(context, ctx.var.uri, nil, context_carrier)
+ span.start(entry_span, ngx.now() * 1000)
+ span.setComponentId(entry_span, NGINX_COMPONENT_ID)
+ span.setLayer(entry_span, span_layer.HTTP)
+
+ span.tag(entry_span, 'http.method', ngx.req.get_method())
+ span.tag(entry_span, 'http.params', ctx.var.scheme .. '://'
+ .. ctx.var.host .. ctx.var.request_uri)
+
+ context_carrier = {}
+ local exit_span = tracing_context.createExitSpan(context,
+ ctx.var.upstream_uri,
+ entry_span,
+ upstream_name,
+ context_carrier)
+ span.start(exit_span, ngx.now() * 1000)
+ span.setComponentId(exit_span, NGINX_COMPONENT_ID)
+ span.setLayer(exit_span, span_layer.HTTP)
+
+ for name, value in pairs(context_carrier) do
+ ngx.req.set_header(name, value)
+ end
+
+ -- Push the data in the context
+ ctx.sw_tracing_context = context
+ ctx.sw_entry_span = entry_span
+ ctx.sw_exit_span = exit_span
+
+ core.log.debug("push data into skywalking context")
+end
+
+function _M.finish(ctx)
+ -- Finish the exit span when received the first response package from upstream
+ if ctx.sw_exit_span then
+ span.finish(ctx.sw_exit_span, ngx.now() * 1000)
+ ctx.sw_exit_span = nil
+ end
+end
+
+function _M.prepareForReport(ctx, endpoint)
+ if ctx.sw_entry_span then
+ span.finish(ctx.sw_entry_span, ngx.now() * 1000)
+ local status, segment = tracing_context.drainAfterFinished(ctx.sw_tracing_context)
+ if status then
+ local segment_json = core.json.encode(sw_segment.transform(segment))
+ core.log.debug('segment = ', segment_json)
+
+ local tracing_buffer = ngx.shared['skywalking-tracing-buffer']
+ local length = tracing_buffer:lpush(endpoint .. '_segment', segment_json)
+ core.log.debug('segment buffer size = ', length)
+ end
+ end
+end
+
+return _M
diff --git a/apisix/plugins/zipkin.lua b/apisix/plugins/zipkin.lua
index 5641239..934d883 100644
--- a/apisix/plugins/zipkin.lua
+++ b/apisix/plugins/zipkin.lua
@@ -48,7 +48,7 @@ local schema = {
local _M = {
version = 0.1,
- priority = -1000, -- last running plugin, but before serverless post func
+ priority = -1000,
name = plugin_name,
schema = schema,
}
diff --git a/bin/apisix b/bin/apisix
index f066c8a..98039a2 100755
--- a/bin/apisix
+++ b/bin/apisix
@@ -179,6 +179,7 @@ http {
lua_shared_dict upstream-healthcheck 10m;
lua_shared_dict worker-events 10m;
lua_shared_dict lrucache-lock 10m;
+ lua_shared_dict skywalking-tracing-buffer 100m;
# for openid-connect plugin
lua_shared_dict discovery 1m; # cache for discovery metadata documents
diff --git a/conf/config.yaml b/conf/config.yaml
index 11d0d76..7475bae 100644
--- a/conf/config.yaml
+++ b/conf/config.yaml
@@ -159,5 +159,7 @@ plugins: # plugin list
- syslog
- batch-requests
- http-logger
+ - skywalking
+
stream_plugins:
- mqtt-proxy
diff --git a/doc/plugin-develop-cn.md b/doc/plugin-develop-cn.md
index c8a7663..1494d52 100644
--- a/doc/plugin-develop-cn.md
+++ b/doc/plugin-develop-cn.md
@@ -95,6 +95,12 @@ plugins: # plugin list
注:先后顺序与执行顺序无关。
+特别需要注意的是,如果你的插件有新建自己的代码目录,那么就需要修改 Makefile 文件,新增创建文件夹的操作,比如:
+```
+$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/skywalking
+$(INSTALL) apisix/plugins/skywalking/*.lua $(INST_LUADIR)/apisix/plugins/skywalking/
+```
+
## 配置描述与校验
定义插件的配置项,以及对应的 [Json Schema](https://json-schema.org) 描述,并完成对 json 的校验,这样方便对配置的数据规
diff --git a/doc/plugin-develop.md b/doc/plugin-develop.md
index f6a6cb6..a2c8b8b 100644
--- a/doc/plugin-develop.md
+++ b/doc/plugin-develop.md
@@ -98,6 +98,12 @@ plugins: # plugin list
Note : the order of the plugins is not related to the order of execution.
+If your plugin has a new code directory of its own, you will need to modify the `Makefile` to create directory, such as:
+```
+$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/skywalking
+$(INSTALL) apisix/plugins/skywalking/*.lua $(INST_LUADIR)/apisix/plugins/skywalking/
+```
+
## schema and check
Write [Json Schema](https://json-schema.org) descriptions and check functions. similarly, take the key-auth plugin as an example to see its
diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec
index aefe8cf..17014c5 100644
--- a/rockspec/apisix-master-0.rockspec
+++ b/rockspec/apisix-master-0.rockspec
@@ -51,6 +51,7 @@ dependencies = {
"lua-resty-ipmatcher = 0.6",
"lua-resty-kafka = 0.07",
"lua-resty-logger-socket = 2.0-0",
+ "skywalking-nginx-lua-plugin = 1.0",
}
build = {
diff --git a/t/APISIX.pm b/t/APISIX.pm
index b8aa664..173aa5c 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -199,6 +199,7 @@ _EOC_
lua_shared_dict upstream-healthcheck 32m;
lua_shared_dict worker-events 10m;
lua_shared_dict lrucache-lock 10m;
+ lua_shared_dict skywalking-tracing-buffer 100m;
resolver $dns_addrs_str;
resolver_timeout 5;
diff --git a/t/admin/plugins.t b/t/admin/plugins.t
index 0c838e6..0cb4c66 100644
--- a/t/admin/plugins.t
+++ b/t/admin/plugins.t
@@ -30,7 +30,7 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
-qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger","proxy-mirror","kafka-logger","cors","syslog","batch-requests","http-logger"\]/
+qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger","proxy-mirror","kafka-logger","cors","syslog","batch-requests","http-logger","skywalking"\]/
--- no_error_log
[error]
diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t
index 1799f50..4efadfe 100644
--- a/t/debug/debug-mode.t
+++ b/t/debug/debug-mode.t
@@ -83,6 +83,7 @@ loaded plugin and sort by priority: 401 name: syslog
loaded plugin and sort by priority: 400 name: udp-logger
loaded plugin and sort by priority: 0 name: example-plugin
loaded plugin and sort by priority: -1000 name: zipkin
+loaded plugin and sort by priority: -1100 name: skywalking
loaded plugin and sort by priority: -2000 name: serverless-post-function
diff --git a/t/lib/server.lua b/t/lib/server.lua
index 0f8fbe3..32a419c 100644
--- a/t/lib/server.lua
+++ b/t/lib/server.lua
@@ -90,7 +90,6 @@ function _M.opentracing()
ngx.say("opentracing")
end
-
function _M.with_header()
ngx.header['Content-Type'] = 'application/xml'
ngx.header['X-Server-id'] = 100
@@ -100,6 +99,24 @@ function _M.with_header()
ngx.say("!")
end
+function _M.mock_skywalking_v2_service_register()
+ ngx.say('[{"key":"APISIX","value":1}]')
+end
+
+function _M.mock_skywalking_v2_instance_register()
+ ngx.req.read_body()
+ local data = ngx.req.get_body_data()
+ data = json_decode(data)
+ local key = data['instances'][1]['instanceUUID']
+ local ret = {}
+ ret[1] = {key = key, value = 1}
+ ngx.say(json_encode(ret))
+end
+
+function _M.mock_skywalking_v2_instance_heartbeat()
+ ngx.say('ok')
+end
+
function _M.mock_zipkin()
ngx.req.read_body()
local data = ngx.req.get_body_data()
diff --git a/t/plugin/skywalking.t b/t/plugin/skywalking.t
new file mode 100644
index 0000000..7e448be
--- /dev/null
+++ b/t/plugin/skywalking.t
@@ -0,0 +1,242 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+BEGIN {
+ if ($ENV{TEST_NGINX_CHECK_LEAK}) {
+ $SkipReason = "unavailable for the hup tests";
+
+ } else {
+ $ENV{TEST_NGINX_USE_HUP} = 1;
+ undef $ENV{TEST_NGINX_USE_STAP};
+ }
+}
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+log_level("debug");
+run_tests;
+
+__DATA__
+
+=== TEST 1: add plugin
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "skywalking": {
+ "endpoint": "http://127.0.0.1:1982/mock_skywalking",
+ "sample_ratio": 1,
+ "service_name": "APISIX"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ }]],
+ [[{
+ "node": {
+ "value": {
+ "plugins": {
+ "skywalking": {
+ "endpoint": "http://127.0.0.1:1982/mock_skywalking",
+ "sample_ratio": 1,
+ "service_name":"APISIX"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ },
+ "key": "/apisix/routes/1"
+ },
+ "action": "set"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: tiger skywalking
+--- request
+GET /opentracing
+--- response_body
+opentracing
+--- no_error_log
+[error]
+--- grep_error_log eval
+qr/skywalking service Instance registered, service instance id: \d+/
+--- grep_error_log_out eval
+qr/skywalking service Instance registered, service instance id: 1/
+
+
+
+=== TEST 3: change sample ratio
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "skywalking": {
+ "endpoint": "http://127.0.0.1:1982/mock_skywalking",
+ "sample_ratio": 0.00001
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ }]],
+ [[{
+ "node": {
+ "value": {
+ "plugins": {
+ "skywalking": {
+ "endpoint": "http://127.0.0.1:1982/mock_skywalking",
+ "sample_ratio": 0.00001
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ },
+ "key": "/apisix/routes/1"
+ },
+ "action": "set"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 4: not tiger skywalking
+--- request
+GET /opentracing
+--- response_body
+opentracing
+--- no_error_log
+push data into skywalking context
+
+
+
+=== TEST 5: disabled
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ }]],
+ [[{
+ "node": {
+ "value": {
+ "plugins": {
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ },
+ "key": "/apisix/routes/1"
+ },
+ "action": "set"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 6: not tiger skywalking
+--- request
+GET /opentracing
+--- response_body
+opentracing
+--- no_error_log
+rewrite phase of skywalking plugin