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

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-go.git


The following commit(s) were added to refs/heads/main by this push:
     new e427c3e  Add support trace ignore (#177)
e427c3e is described below

commit e427c3e53a7fda57ebd85b9784e58db352d77a53
Author: Starry <codeprince2...@163.com>
AuthorDate: Fri Mar 22 09:23:52 2024 +0800

    Add support trace ignore (#177)
---
 CHANGES.md                                        |   5 +-
 docs/en/agent/tracing-metrics-logging.md          |   9 +-
 plugins/core/tracer.go                            |   4 +-
 plugins/core/tracer_ignore.go                     | 135 ++++++++++++++++++++++
 plugins/core/tracer_ignore_test.go                |  81 +++++++++++++
 plugins/core/tracing.go                           |  16 +--
 tools/go-agent/config/agent.default.yaml          |   8 +-
 tools/go-agent/config/loader.go                   |   1 +
 tools/go-agent/instrument/agentcore/instrument.go |   3 +-
 9 files changed, 239 insertions(+), 23 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index f823c49..fe3da3b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,6 +4,9 @@ Release Notes.
 
 0.5.0
 ------------------
+#### Features
+* Add support trace ignore.
+
 #### Plugins
 * Support [Pulsar](https://github.com/apache/pulsar-client-go) MQ.
 * Support [Segmentio-Kafka](https://github.com/segmentio/kafka-go) MQ.
@@ -111,7 +114,7 @@ Release Notes.
 * Support [Kratos](github.com/go-kratos/kratos) v2 server and client framework.
 * Support [Go-Micro](https://github.com/go-micro/go-micro) v4 server and 
client framework.
 * Support [GORM](https://github.com/go-gorm/gorm) v2 database client framework.
-  * Support [MySQL Driver](https://github.com/go-gorm/mysql) detection.
+* Support [MySQL Driver](https://github.com/go-gorm/mysql) detection.
 
 #### Documentation
 * Initialize the documentation.
diff --git a/docs/en/agent/tracing-metrics-logging.md 
b/docs/en/agent/tracing-metrics-logging.md
index 07ccf8d..ec6e263 100644
--- a/docs/en/agent/tracing-metrics-logging.md
+++ b/docs/en/agent/tracing-metrics-logging.md
@@ -22,10 +22,11 @@ If you wish to disable a particular plugin to prevent 
enhancements related to th
 
 The basic configuration is as follows:
 
-| Name                | Environment Key        | Default Value                 
                               | Description                                    
                                                                          |
-|---------------------|------------------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
-| agent.sampler       | SW_AGENT_SAMPLER       | 1                             
                               | Sampling rate of tracing data, which is a 
floating-point value that must be between 0 and 1.                             |
-| agent.ignore_suffix | SW_AGENT_IGNORE_SUFFIX | 
.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg | If the operation 
name of the first span is included in this set, this segment should be 
ignored.(multiple split by ","). |
+| Name                    | Environment Key            | Default Value         
                                       | Description                            
                                                                                
                              |
+|-------------------------|----------------------------|--------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
+| agent.sampler           | SW_AGENT_SAMPLER           | 1                     
                                       | Sampling rate of tracing data, which 
is a floating-point value that must be between 0 and 1.                         
                                |
+| agent.ignore_suffix     | SW_AGENT_IGNORE_SUFFIX     | 
.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg | If the suffix 
obtained by splitting the operation name by the last index of "." in this set, 
this segment should be ignored.(multiple split by ","). |
+| agent.trace_ignore_path | SW_AGENT_TRACE_IGNORE_PATH |                       
                                       | If the operation name of the first 
span is matching, this segment should be ignored.(multiple split by ",").       
                                  |
 
 ## Metrics
 
diff --git a/plugins/core/tracer.go b/plugins/core/tracer.go
index e10a56b..53a5eff 100644
--- a/plugins/core/tracer.go
+++ b/plugins/core/tracer.go
@@ -54,10 +54,11 @@ type Tracer struct {
        meterMap              *sync.Map
        meterCollectListeners []func()
        ignoreSuffix          []string
+       traceIgnorePath       []string
 }
 
 func (t *Tracer) Init(entity *reporter.Entity, rep reporter.Reporter, samp 
Sampler, logger operator.LogOperator,
-       meterCollectSecond int, correlation *CorrelationConfig, ignoreSuffixStr 
string) error {
+       meterCollectSecond int, correlation *CorrelationConfig, ignoreSuffixStr 
string, ignorePath string) error {
        t.ServiceEntity = entity
        t.Reporter = rep
        t.Sampler = samp
@@ -69,6 +70,7 @@ func (t *Tracer) Init(entity *reporter.Entity, rep 
reporter.Reporter, samp Sampl
        t.initMetricsCollect(meterCollectSecond)
        t.correlation = correlation
        t.ignoreSuffix = strings.Split(ignoreSuffixStr, ",")
+       t.traceIgnorePath = strings.Split(ignorePath, ",")
        // notify the tracer been init success
        if len(GetInitNotify()) > 0 {
                for _, fun := range GetInitNotify() {
diff --git a/plugins/core/tracer_ignore.go b/plugins/core/tracer_ignore.go
new file mode 100644
index 0000000..ae4212b
--- /dev/null
+++ b/plugins/core/tracer_ignore.go
@@ -0,0 +1,135 @@
+// Licensed to 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. Apache Software Foundation (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.
+
+package core
+
+import (
+       "strings"
+)
+
+func tracerIgnore(operationName string, ignoreSuffixList, ignorePath []string) 
bool {
+       return ignoreSuffix(operationName, ignoreSuffixList) || 
traceIgnorePath(operationName, ignorePath)
+}
+
+func ignoreSuffix(operationName string, ignoreSuffix []string) bool {
+       suffixIdx := strings.LastIndex(operationName, ".")
+       if suffixIdx == -1 {
+               return false
+       }
+       for _, suffix := range ignoreSuffix {
+               if suffix == operationName[suffixIdx:] {
+                       return true
+               }
+       }
+       return false
+}
+
+func traceIgnorePath(operationName string, ignorePath []string) bool {
+       for _, pattern := range ignorePath {
+               if normalMatch(pattern, 0, operationName, 0) {
+                       return true
+               }
+       }
+       return false
+}
+
+// normalMatch determines whether the operation name matches the wildcard 
pattern.
+// The parameters `p` and `s` represent the current index in pattern and 
operationName respectively.
+func normalMatch(pattern string, p int, operationName string, s int) bool {
+       for p < len(pattern) {
+               pc := pattern[p]
+               sc := safeCharAt(operationName, s)
+
+               if pc == '*' {
+                       p++
+                       if safeCharAt(pattern, p) == '*' {
+                               p++
+                               return multiWildcardMatch(pattern, p, 
operationName, s)
+                       }
+                       return wildcardMatch(pattern, p, operationName, s)
+               }
+
+               if (pc == '?' && sc != 0 && sc != '/') || pc == sc {
+                       s++
+                       p++
+                       continue
+               }
+               return false
+       }
+       return s == len(operationName)
+}
+
+func wildcardMatch(pattern string, p int, operationName string, s int) bool {
+       pc := safeCharAt(pattern, p)
+
+       if pc == 0 {
+               for {
+                       sc := safeCharAt(operationName, s)
+                       if sc == 0 {
+                               return true
+                       }
+                       if sc == '/' {
+                               return s == len(operationName)-1
+                       }
+                       s++
+               }
+       }
+
+       for {
+               sc := safeCharAt(operationName, s)
+               if sc == '/' {
+                       if pc == sc {
+                               return normalMatch(pattern, p+1, operationName, 
s+1)
+                       }
+                       return false
+               }
+               if !normalMatch(pattern, p, operationName, s) {
+                       if s >= len(operationName) {
+                               return false
+                       }
+                       s++
+                       continue
+               }
+               return true
+       }
+}
+
+func multiWildcardMatch(pattern string, p int, operationName string, s int) 
bool {
+       switch safeCharAt(pattern, p) {
+       case 0:
+               return true
+       case '/':
+               p++
+       }
+       for {
+               if !normalMatch(pattern, p, operationName, s) {
+                       if s >= len(operationName) {
+                               return false
+                       }
+                       s++
+                       continue
+               }
+               return true
+       }
+}
+
+func safeCharAt(value string, index int) byte {
+       if index >= len(value) {
+               return 0
+       }
+       return value[index]
+}
diff --git a/plugins/core/tracer_ignore_test.go 
b/plugins/core/tracer_ignore_test.go
new file mode 100644
index 0000000..9bd3bf3
--- /dev/null
+++ b/plugins/core/tracer_ignore_test.go
@@ -0,0 +1,81 @@
+// Licensed to 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. Apache Software Foundation (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.
+
+package core
+
+import (
+       "strings"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestIgnoreSuffix(t *testing.T) {
+       ignoreSuffixStr := 
".jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg"
+       ignoreSuffixList := strings.Split(ignoreSuffixStr, ",")
+       assert.True(t, ignoreSuffix("GET:/favicon.ico", ignoreSuffixList))
+}
+
+func TestTraceIgnorePath(t *testing.T) {
+       ignorePath := []string{"/health/*"}
+       assert.False(t, traceIgnorePath("", ignorePath))
+       assert.True(t, traceIgnorePath("/health/apps", ignorePath))
+       assert.True(t, traceIgnorePath("/health/", ignorePath))
+       assert.True(t, traceIgnorePath("/health/apps/", ignorePath))
+
+       ignorePath = []string{"/health/**"}
+       assert.True(t, traceIgnorePath("/health/apps/", ignorePath))
+
+       ignorePath = []string{"/health/?"}
+       assert.True(t, traceIgnorePath("/health/a", ignorePath))
+       assert.False(t, traceIgnorePath("/health/ab", ignorePath))
+
+       ignorePath = []string{"/health/*/"}
+       assert.True(t, traceIgnorePath("/health/apps/", ignorePath))
+       assert.False(t, traceIgnorePath("/health/", ignorePath))
+       assert.False(t, traceIgnorePath("/health/apps/list", ignorePath))
+       assert.False(t, traceIgnorePath("/health/test", ignorePath))
+
+       ignorePath = []string{"/health/**"}
+       assert.True(t, traceIgnorePath("/health/", ignorePath))
+       assert.True(t, traceIgnorePath("/health/apps/test", ignorePath))
+       assert.True(t, traceIgnorePath("/health/apps/test/", ignorePath))
+
+       ignorePath = []string{"health/apps/?"}
+       assert.False(t, traceIgnorePath("health/apps/list", ignorePath))
+       assert.False(t, traceIgnorePath("health/apps/", ignorePath))
+       assert.True(t, traceIgnorePath("health/apps/a", ignorePath))
+
+       ignorePath = []string{"health/**/lists"}
+       assert.True(t, traceIgnorePath("health/apps/lists", ignorePath))
+       assert.True(t, traceIgnorePath("health/apps/test/lists", ignorePath))
+       assert.False(t, traceIgnorePath("health/apps/test/", ignorePath))
+       assert.False(t, traceIgnorePath("health/apps/test", ignorePath))
+
+       ignorePath = []string{"health/**/test/**"}
+       assert.True(t, traceIgnorePath("health/apps/test/list", ignorePath))
+       assert.True(t, traceIgnorePath("health/apps/foo/test/list/bar", 
ignorePath))
+       assert.True(t, traceIgnorePath("health/apps/foo/test/list/bar/", 
ignorePath))
+       assert.True(t, traceIgnorePath("health/apps/test/list", ignorePath))
+       assert.True(t, traceIgnorePath("health/test/list", ignorePath))
+
+       ignorePath = []string{"/health/**/b/**/*.txt", "abc/*"}
+       assert.True(t, traceIgnorePath("/health/a/aa/aaa/b/bb/bbb/xxxxxx.txt", 
ignorePath))
+       assert.False(t, traceIgnorePath("/health/a/aa/aaa/b/bb/bbb/xxxxxx", 
ignorePath))
+       assert.False(t, traceIgnorePath("abc/foo/bar", ignorePath))
+       assert.True(t, traceIgnorePath("abc/foo", ignorePath))
+}
diff --git a/plugins/core/tracing.go b/plugins/core/tracing.go
index 8fac32f..1f73c89 100644
--- a/plugins/core/tracing.go
+++ b/plugins/core/tracing.go
@@ -20,7 +20,6 @@ package core
 import (
        "reflect"
        "runtime/debug"
-       "strings"
 
        "github.com/pkg/errors"
 
@@ -230,7 +229,7 @@ func (t *Tracer) createNoop(operationName string) 
(*TracingContext, TracingSpan,
        if !t.InitSuccess() || t.Reporter.ConnectionStatus() == 
reporter.ConnectionStatusDisconnect {
                return nil, newNoopSpan(), true
        }
-       if ignoreSuffixFilter(operationName, t.ignoreSuffix) {
+       if tracerIgnore(operationName, t.ignoreSuffix, t.traceIgnorePath) {
                return nil, newNoopSpan(), true
        }
        ctx := getTracingContext()
@@ -341,16 +340,3 @@ func saveSpanToActiveIfNotError(ctx *TracingContext, span 
interface{}, err error
        ctx.SaveActiveSpan(span.(TracingSpan))
        SetGLS(ctx)
 }
-
-func ignoreSuffixFilter(operationName string, ignoreSuffix []string) bool {
-       suffixIdx := strings.LastIndex(operationName, ".")
-       if suffixIdx == -1 {
-               return false
-       }
-       for _, suffix := range ignoreSuffix {
-               if suffix == operationName[suffixIdx:] {
-                       return true
-               }
-       }
-       return false
-}
diff --git a/tools/go-agent/config/agent.default.yaml 
b/tools/go-agent/config/agent.default.yaml
index 0af4207..ee1e5cd 100644
--- a/tools/go-agent/config/agent.default.yaml
+++ b/tools/go-agent/config/agent.default.yaml
@@ -30,8 +30,14 @@ agent:
   correlation:
     max_key_count: ${SW_AGENT_CORRELATION_MAX_KEY_COUNT:3}
     max_value_size: ${SW_AGENT_CORRELATION_MAX_VALUE_SIZE:128}
-  # If the operation name of the first span is included in this set, this 
segment should be ignored.(multiple split by ",")
+  # If the suffix obtained by splitting the operation name by the last index 
of "." in this set, this segment should be ignored.(multiple split by ",").
   ignore_suffix: 
${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}
+  # If the operation name of the first span is matching, this segment should 
be ignored.(multiple split by ",").
+  # Matching rules follow Ant Path match style, like /path/*, /path/**, 
/path/?.
+  #       "/path/*" means matching any path that starts with "/path/".  
+  #       "/path/**" means matching any path that starts with "/path/" and 
includes its subpaths.
+  #       "/path/?" means matching any path that starts with "/path/" and has 
any single character as a wildcard.
+  trace_ignore_path: ${SW_AGENT_TRACE_IGNORE_PATH:}
 
 reporter:
   discard: ${SW_AGENT_REPORTER_DISCARD:false}
diff --git a/tools/go-agent/config/loader.go b/tools/go-agent/config/loader.go
index e42420d..466626a 100644
--- a/tools/go-agent/config/loader.go
+++ b/tools/go-agent/config/loader.go
@@ -51,6 +51,7 @@ type Agent struct {
        Meter           Meter       `yaml:"meter"`
        Correlation     Correlation `yaml:"correlation"`
        IgnoreSuffix    StringValue `yaml:"ignore_suffix"`
+       TraceIgnorePath StringValue `yaml:"trace_ignore_path"`
 }
 
 type Reporter struct {
diff --git a/tools/go-agent/instrument/agentcore/instrument.go 
b/tools/go-agent/instrument/agentcore/instrument.go
index 83dcbb6..b46abec 100644
--- a/tools/go-agent/instrument/agentcore/instrument.go
+++ b/tools/go-agent/instrument/agentcore/instrument.go
@@ -163,7 +163,8 @@ func (t *Tracer) InitTracer(extend map[string]interface{}) {
                MaxValueSize : 
{{.Config.Agent.Correlation.MaxValueSize.ToGoIntValue "loading the agent 
correlation maxValueSize error"}},
        }
        ignoreSuffixStr := {{.Config.Agent.IgnoreSuffix.ToGoStringValue}}
-       if err := t.Init(entity, rep, samp, logger, meterCollectInterval, 
correlation, ignoreSuffixStr); err != nil {
+       ignorePath := {{.Config.Agent.TraceIgnorePath.ToGoStringValue}}
+       if err := t.Init(entity, rep, samp, logger, meterCollectInterval, 
correlation, ignoreSuffixStr, ignorePath); err != nil {
                t.Log.Errorf("cannot initialize the SkyWalking Tracer: %v", err)
        }
 }`, struct {

Reply via email to