This is an automated email from the ASF dual-hosted git repository.

shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new bb70ec008 perf(zipkin): skip span tag construction for unsampled 
requests (#13656)
bb70ec008 is described below

commit bb70ec008158a85cd0235fc64e1b8ad9e300c2ad
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Mon Jul 6 19:07:32 2026 +0800

    perf(zipkin): skip span tag construction for unsampled requests (#13656)
---
 apisix/plugins/zipkin.lua            | 46 ++++++++++++++++++++----------------
 docs/en/latest/plugins/skywalking.md |  6 +++++
 docs/en/latest/plugins/zipkin.md     |  6 +++++
 t/plugin/zipkin3.t                   | 10 ++++++++
 4 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/apisix/plugins/zipkin.lua b/apisix/plugins/zipkin.lua
index 615828bc5..fd46d0ede 100644
--- a/apisix/plugins/zipkin.lua
+++ b/apisix/plugins/zipkin.lua
@@ -182,19 +182,34 @@ function _M.rewrite(plugin_conf, ctx)
 
     local wire_context = tracer:extract("http_headers", ctx)
 
-    local start_timestamp = ngx.req.start_time()
-    local request_span = tracer:start_span("apisix.request", {
-        child_of = wire_context,
-        start_timestamp = start_timestamp,
+    -- Decide sampling before building the span. The reporter drops unsampled
+    -- spans, so skip tag construction and remote-addr lookups for them.
+    if sampled == "1" or sampled == "true" then
+        per_req_sample_ratio = 1
+    elseif sampled == "0" or sampled == "false" then
+        per_req_sample_ratio = 0
+    end
+    local sample = tracer.sampler:sample(per_req_sample_ratio or 
conf.sample_ratio)
+    ctx.opentracing_sample = sample
+
+    local tags
+    if sample then
         tags = {
             component = "apisix",
             ["span.kind"] = "server",
             ["http.method"] = ctx.var.request_method,
             ["http.url"] = ctx.var.request_uri,
-             -- TODO: support ipv6
+            -- TODO: support ipv6
             ["peer.ipv4"] = core.request.get_remote_client_ip(ctx),
             ["peer.port"] = core.request.get_remote_client_port(ctx),
         }
+    end
+
+    local start_timestamp = ngx.req.start_time()
+    local request_span = tracer:start_span("apisix.request", {
+        child_of = wire_context,
+        start_timestamp = start_timestamp,
+        tags = tags,
     })
 
     ctx.opentracing = {
@@ -203,18 +218,10 @@ function _M.rewrite(plugin_conf, ctx)
         request_span = request_span,
     }
 
-    -- Process sampled
-    if sampled == "1" or sampled == "true" then
-        per_req_sample_ratio = 1
-    elseif sampled == "0" or sampled == "false" then
-        per_req_sample_ratio = 0
-    end
-
-    ctx.opentracing_sample = tracer.sampler:sample(per_req_sample_ratio or 
conf.sample_ratio)
-    if not ctx.opentracing_sample then
-        request_span:set_baggage_item("x-b3-sampled","0")
+    if not sample then
+        request_span:set_baggage_item("x-b3-sampled", "0")
     else
-       request_span:set_baggage_item("x-b3-sampled","1")
+        request_span:set_baggage_item("x-b3-sampled", "1")
     end
 
     if plugin_info.set_ngx_var then
@@ -227,11 +234,10 @@ function _M.rewrite(plugin_conf, ctx)
         ngx_var.zipkin_span_id = to_hex(span_context.span_id)
     end
 
-    if not ctx.opentracing_sample then
+    if not sample then
         return
     end
 
-    local request_span = ctx.opentracing.request_span
     if conf.span_version == ZIPKIN_SPAN_VER_1 then
         ctx.opentracing.rewrite_span = 
request_span:start_child_span("apisix.rewrite",
                                                                      
start_timestamp)
@@ -245,9 +251,9 @@ end
 
 function _M.access(conf, ctx)
     local opentracing = ctx.opentracing
-    local tracer = opentracing.tracer
 
-    if conf.span_version == ZIPKIN_SPAN_VER_1 then
+    if ctx.opentracing_sample and conf.span_version == ZIPKIN_SPAN_VER_1 then
+        local tracer = opentracing.tracer
         opentracing.access_span = opentracing.request_span:start_child_span(
             "apisix.access", ctx.REWRITE_END_TIME)
 
diff --git a/docs/en/latest/plugins/skywalking.md 
b/docs/en/latest/plugins/skywalking.md
index d54c0d6f5..d664295c8 100644
--- a/docs/en/latest/plugins/skywalking.md
+++ b/docs/en/latest/plugins/skywalking.md
@@ -63,6 +63,12 @@ Reload APISIX for changes to take effect.
 
|--------------|--------|----------|---------|--------------|----------------------------------------------------------------------------|
 | sample_ratio | number | False     | 1       | [0.00001, 1] | Frequency of 
request sampling. Setting the sample ratio to `1` means to sample all requests. 
|
 
+:::tip Performance
+
+The plugin hooks several request phases and builds a trace per sampled 
request, so tracing adds per-request overhead. Sampling is the primary lever to 
control it: unsampled requests skip trace creation entirely. Lower 
`sample_ratio` on high-throughput routes to reduce overhead while keeping 
representative traces.
+
+:::
+
 ## Example
 
 To follow along the example, start a storage, OAP and Booster UI with Docker 
Compose, following [Skywalking's 
documentation](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/).
 Once set up, the OAP server should be listening on `12800` and you should be 
able to access the UI at [http://localhost:8080](http://localhost:8080).
diff --git a/docs/en/latest/plugins/zipkin.md b/docs/en/latest/plugins/zipkin.md
index 78063a482..dccb10516 100644
--- a/docs/en/latest/plugins/zipkin.md
+++ b/docs/en/latest/plugins/zipkin.md
@@ -63,6 +63,12 @@ See the configuration file for configuration options 
available to all Plugins.
 |server_addr | string  | False    |the value of `$server_addr` | IPv4 address 
| IPv4 address for the Zipkin reporter. For example, you can set this to your 
external IP address. |
 |span_version | integer | False    | 2             | [1, 2]       | Version of 
the span type. |
 
+:::tip Performance
+
+The plugin hooks several request phases and builds a span per sampled request, 
so tracing adds per-request overhead. Sampling is the primary lever to control 
it: `sample_ratio` is the fraction of requests traced, and unsampled requests 
skip span tag construction entirely. Lower `sample_ratio` on high-throughput 
routes to reduce overhead while keeping representative traces.
+
+:::
+
 ## Examples
 
 The examples below show different use cases of the `zipkin` Plugin.
diff --git a/t/plugin/zipkin3.t b/t/plugin/zipkin3.t
index d4bcd721c..d0c783523 100644
--- a/t/plugin/zipkin3.t
+++ b/t/plugin/zipkin3.t
@@ -159,3 +159,13 @@ plugin_attr:
 GET /echo
 --- error_log
 ngx_var.zipkin_context_traceparent is empty
+
+
+
+=== TEST 6: unsampled request still builds span context for set_ngx_var
+--- request
+GET /echo
+--- more_headers
+x-b3-sampled: 0
+--- error_log eval
+qr/ngx_var.zipkin_context_traceparent:00-\w{32}-\w{16}-00/

Reply via email to