diff --git a/Makefile b/Makefile index 16ded88d3cd8..760c692a441c 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 73a4ee22af43..f6b4a4f34a7e 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 2b85609e6f7a..b9143268b24a 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 3303e8dc0d0c..bb7092f40682 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 000000000000..f95286bd8d14 --- /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 000000000000..676735cbc9b6 --- /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 000000000000..edc4bfe0208f --- /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 56412390e379..934d88398ac1 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 f066c8a8a9fa..98039a2d324d 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 11d0d76c35d5..7475baebb7f1 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 c8a7663b8d30..1494d525a668 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 f6a6cb66bbe4..a2c8b8b60f4b 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 aefe8cf6c237..17014c5051ba 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 b8aa664bf941..173aa5cc8bb6 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 0c838e6c6173..0cb4c6658421 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 1799f509bc95..4efadfebb375 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 0f8fbe35d006..32a419c47c27 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 000000000000..7e448bef5f93 --- /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