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

kezhenxu94 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-python.git


The following commit(s) were added to refs/heads/master by this push:
     new 9edca3d  Add trace ignore (#59)
9edca3d is described below

commit 9edca3d6126ac07eaeefc5976de1f9b9cddd69c8
Author: huawei <alonela...@gmail.com>
AuthorDate: Thu Aug 6 23:46:23 2020 +0800

    Add trace ignore (#59)
---
 docs/EnvVars.md                 |  2 +
 skywalking/config.py            |  3 ++
 skywalking/trace/context.py     |  9 +++++
 skywalking/utils/ant_matcher.py | 90 +++++++++++++++++++++++++++++++++++++++++
 tests/test_ant_matcher.py       | 86 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 190 insertions(+)

diff --git a/docs/EnvVars.md b/docs/EnvVars.md
index 7f1714d..babd9b1 100644
--- a/docs/EnvVars.md
+++ b/docs/EnvVars.md
@@ -17,3 +17,5 @@ Environment Variable | Description | Default
 | `SW_HTTP_PARAMS_LENGTH_THRESHOLD`| When `COLLECT_HTTP_PARAMS` is enabled, 
how many characters to keep and send to the OAP backend, use negative values to 
keep and send the complete parameters, NB. this config item is added for the 
sake of performance.  | `1024` |
 | `SW_CORRELATION_ELEMENT_MAX_NUMBER`|Max element count of the correlation 
context.| `3` |
 | `SW_CORRELATION_VALUE_MAX_LENGTH`| Max value length of correlation context 
element.| `128` |
+| `SW_TRACE_IGNORE`| This config item controls that whether the trace should 
be ignore | `false` |
+| `SW_TRACE_IGNORE_PATH`| You can setup multiple URL path patterns, The 
endpoints match these patterns wouldn't be traced. the current matching rules 
follow Ant Path match style , like /path/*, /path/**, /path/?.| `''` |
diff --git a/skywalking/config.py b/skywalking/config.py
index cc2544e..fe73943 100644
--- a/skywalking/config.py
+++ b/skywalking/config.py
@@ -38,6 +38,9 @@ django_collect_http_params = True if 
os.getenv('SW_DJANGO_COLLECT_HTTP_PARAMS')
                                     os.getenv('SW_DJANGO_COLLECT_HTTP_PARAMS') 
== 'True' else False   # type: bool
 correlation_element_max_number = 
int(os.getenv('SW_CORRELATION_ELEMENT_MAX_NUMBER') or '3')  # type: int
 correlation_value_max_length = 
int(os.getenv('SW_CORRELATION_VALUE_MAX_LENGTH') or '128')  # type: int
+trace_ignore = True if os.getenv('SW_TRACE_IGNORE') and \
+                       os.getenv('SW_TRACE_IGNORE') == 'True' else False   # 
type: bool
+trace_ignore_path = (os.getenv('SW_TRACE_IGNORE_PATH') or '').split(',')  # 
type: List[str]
 
 
 def init(
diff --git a/skywalking/trace/context.py b/skywalking/trace/context.py
index 23cdbc6..39b80ef 100644
--- a/skywalking/trace/context.py
+++ b/skywalking/trace/context.py
@@ -25,6 +25,7 @@ from skywalking.trace.carrier import Carrier
 from skywalking.trace.segment import Segment, SegmentRef
 from skywalking.trace.snapshot import Snapshot
 from skywalking.trace.span import Span, Kind, NoopSpan, EntrySpan, ExitSpan
+from skywalking.utils.ant_matcher import fast_path_match
 from skywalking.utils.counter import Counter
 
 logger = logging.getLogger(__name__)
@@ -98,6 +99,14 @@ class SpanContext(object):
                 context=NoopContext(),
                 kind=kind,
             )
+        if config.trace_ignore:
+            for pattern in config.trace_ignore_path:
+                if fast_path_match(pattern, op):
+                    return NoopSpan(
+                        context=NoopContext(),
+                        kind=kind,
+                    )
+
         return None
 
     def start(self, span: Span):
diff --git a/skywalking/utils/ant_matcher.py b/skywalking/utils/ant_matcher.py
new file mode 100644
index 0000000..41e004a
--- /dev/null
+++ b/skywalking/utils/ant_matcher.py
@@ -0,0 +1,90 @@
+#
+# 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.
+#
+
+
+def fast_path_match(pattern: str, path: str):
+    return normal_match(pattern, 0, path, 0)
+
+
+def normal_match(pat: str, p: int, var: str, s: int) -> bool:
+    while p < len(pat):
+        pc = pat[p]
+        sc = safe_char_at(var, s)
+
+        if pc == '*':
+            p += 1
+
+            if safe_char_at(pat, p) == '*':
+                p += 1
+
+                return multi_wildcard_match(pat, p, var, s)
+            else:
+                return wildcard_match(pat, p, var, s)
+
+        if (pc == '?' and sc != '0' and sc != '/') or pc == sc:
+            s += 1
+            p += 1
+            continue
+
+        return False
+
+    return s == len(var)
+
+
+def wildcard_match(pat: str, p: int, var: str, s: int) -> bool:
+    pc = safe_char_at(pat, p)
+
+    while True:
+        sc = safe_char_at(var, s)
+
+        if sc == '/':
+
+            if pc == sc:
+                return normal_match(pat, p + 1, var, s + 1)
+
+            return False
+
+        if normal_match(pat, p, var, s) is False:
+            if s >= len(var):
+                return False
+
+            s += 1
+            continue
+
+        return True
+
+
+def multi_wildcard_match(pat: str, p: int, var: str, s: int) -> bool:
+    if p >= len(pat) and s < len(var):
+        return var[len(var) - 1] != '/'
+
+    while True:
+        if not normal_match(pat, p, var, s):
+            if s >= len(var):
+                return False
+
+            s += 1
+            continue
+
+        return True
+
+
+def safe_char_at(value: str, index: int) -> str:
+    if index >= len(value):
+        return '0'
+
+    return value[index]
diff --git a/tests/test_ant_matcher.py b/tests/test_ant_matcher.py
new file mode 100644
index 0000000..de64c4d
--- /dev/null
+++ b/tests/test_ant_matcher.py
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+import unittest
+
+from skywalking.utils.ant_matcher import fast_path_match
+
+
+class TestFastPathMatch(unittest.TestCase):
+    def test_match(self):
+        patten = "/eureka/*"
+        path = "/eureka/apps"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/apps/"
+        self.assertFalse(fast_path_match(patten, path))
+
+        patten = "/eureka/*/"
+        path = "/eureka/apps/"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/"
+        self.assertFalse(fast_path_match(patten, path))
+        path = "/eureka/apps/list"
+        self.assertFalse(fast_path_match(patten, path))
+
+        patten = "/eureka/**"
+        path = "/eureka/"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/apps/test"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/apps/test/"
+        self.assertFalse(fast_path_match(patten, path))
+
+        patten = "eureka/apps/?"
+        path = "eureka/apps/list"
+        self.assertFalse(fast_path_match(patten, path))
+        path = "eureka/apps/"
+        self.assertFalse(fast_path_match(patten, path))
+        path = "eureka/apps/a"
+        self.assertTrue(fast_path_match(patten, path))
+
+        patten = "eureka/**/lists"
+        path = "eureka/apps/lists"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "eureka/apps/test/lists"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "eureka/apps/test/"
+        self.assertFalse(fast_path_match(patten, path))
+        path = "eureka/apps/test"
+        self.assertFalse(fast_path_match(patten, path))
+
+        patten = "eureka/**/test/**"
+        path = "eureka/apps/test/list"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "eureka/apps/foo/test/list/bar"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "eureka/apps/foo/test/list/bar/"
+        self.assertFalse(fast_path_match(patten, path))
+        path = "eureka/apps/test/list"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "eureka/test/list"
+        self.assertFalse(fast_path_match(patten, path))
+
+        patten = "/eureka/**/b/**/*.txt"
+        path = "/eureka/a/aa/aaa/b/bb/bbb/xxxxxx.txt"
+        self.assertTrue(fast_path_match(patten, path))
+        path = "/eureka/a/aa/aaa/b/bb/bbb/xxxxxx"
+        self.assertFalse(fast_path_match(patten, path))
+
+
+if __name__ == '__main__':
+    unittest.main()

Reply via email to