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 71df914  refactor: hide some functions related to meter from users 
(#236)
71df914 is described below

commit 71df9145f080c37d8de4f5129bca4a97e5683951
Author: jiang1997 <[email protected]>
AuthorDate: Thu Sep 15 18:54:52 2022 +0800

    refactor: hide some functions related to meter from users (#236)
---
 docs/en/setup/advanced/MeterReporter.md | 45 +++++++++++++++------------------
 skywalking/meter/counter.py             | 12 ++++++---
 skywalking/meter/gauge.py               |  4 +++
 skywalking/meter/histogram.py           |  8 +++++-
 skywalking/meter/meter.py               | 32 ++++++++++++++---------
 tests/unit/test_meter.py                | 33 ++++++++++++------------
 6 files changed, 77 insertions(+), 57 deletions(-)

diff --git a/docs/en/setup/advanced/MeterReporter.md 
b/docs/en/setup/advanced/MeterReporter.md
index f9cceb2..6286a99 100644
--- a/docs/en/setup/advanced/MeterReporter.md
+++ b/docs/en/setup/advanced/MeterReporter.md
@@ -23,17 +23,16 @@ export SW_AGENT_METER_REPORTER_ACTIVE=False
 ## Counter
 * `Counter` API represents a single monotonically increasing counter, 
automatic collect data and report to backend.
 ```python
-tg_ls = [MeterTag("key", "value")]
-c = Counter('c2', CounterMode.INCREMENT, tg_ls)
-# or with more compact way
-# Counter('c2', CounterMode.INCREMENT).tag('key1', 'value1').tag('key2', 
'value2')
-c.build()
+builder = Counter.Builder('c2', CounterMode.INCREMENT, (("k1", "v1"), ("k2", 
"v2")))
+# or this way
+# builder = Counter.Builder('c2', CounterMode.INCREMENT).tag('key1', 
'value1').tag('key2', 'value2')
+c = builder.build()
 c.increment(2)
 ```
 ### Syntactic sugars
 ```python
-c = Counter('c2', CounterMode.INCREMENT)
-c.build()
+builder = Counter.Builder('c2', CounterMode.INCREMENT)
+c = builder.build()
 
 # increase Counter c by the time the with-wrapped codes consumed
 with c.create_timer():
@@ -41,8 +40,8 @@ with c.create_timer():
 ```
 
 ```python
-c = Counter('c3', CounterMode.INCREMENT)
-c.build()
+builder = Counter.Builder('c3', CounterMode.INCREMENT)
+c = builder.build()
 
 # increase Counter c by num once counter_decorator_test gets called
 @Counter.increase(name='c3', num=2)
@@ -51,8 +50,8 @@ def counter_decorator_test():
 ```
 
 ```python
-c = Counter('c4', CounterMode.INCREMENT)
-c.build()
+builder = Counter.Builder('c4', CounterMode.INCREMENT)
+c = builder.build()
 
 # increase Counter c by the time counter_decorator_test consumed
 @Counter.timer(name='c4')
@@ -60,7 +59,7 @@ def counter_decorator_test(s):
     # some codes may consume a certain time
 ```
 
-1. `Counter(name, tags)` Create a new counter with the meter name and optional 
tags.
+1. `Counter.Builder(name, tags)` Create a new counter builder with the meter 
name and optional tags.
 1. `Counter.tag(key: str, value)` Mark a tag key/value pair.
 1. `Counter.mode(mode: CounterMode)` Change the counter mode, RATE mode means 
reporting rate to the backend.
 1. `Counter.increment(count)` Increment count to the `Counter`, It could be a 
positive value.
@@ -68,26 +67,24 @@ def counter_decorator_test(s):
 ## Gauge
 * `Gauge` API represents a single numerical value.
 ```python
-tg_ls = [MeterTag("key", "value")]
 # producer: iterable object
-g = Gauge('g1', producer, tg_ls)
-g.build()
+builder = Gauge.Builder('g1', producer, (("key", "value")))
+g = Builder.build()
 ```
-1. `Gauge(name, tags)` Create a new gauge with the meter name and iterable 
object, this iterable object need to produce numeric value.
+1. `Gauge.Builder(name, tags)` Create a new gauge builder with the meter name 
and iterable object, this iterable object need to produce numeric value.
 1. `Gauge.tag(key: str, value)` Mark a tag key/value pair.
 1. `Gauge.build()` Build a new `Gauge` which is collected and reported to the 
backend.
 
 ## Histogram
 * `Histogram` API represents a summary sample observations with customize 
buckets.
 ```python
-tg_ls = [MeterTag("key", "value")]
-h = Histogram('h2', [i / 10 for i in range(10)], tg_ls)
-h.build()
+builder = Histogram.Builder('h2', [i / 10 for i in range(10)], ("key", 
"value"))
+h = builder.build()
 ```
 ### Syntactic sugars
 ```python
-h = Histogram('h3', [i / 10 for i in range(10)])
-h.build()
+builder = Histogram.Builder('h3', [i / 10 for i in range(10)])
+h = builder.build()
 
 # Histogram h will record the time the with-wrapped codes consumed
 with h.create_timer():
@@ -95,15 +92,15 @@ with h.create_timer():
 ```
 
 ```python
-h = Histogram('h2', [i / 10 for i in range(10)])
-h.build()
+builder = Histogram.Builder('h2', [i / 10 for i in range(10)])
+h = builder.build()
 
 # Histogram h will record the time histogram_decorator_test consumed
 @Histogram.timer(name='h2')
 def histogram_decorator_test(s):
     time.sleep(s)
 ```
-1. `Histogram(name, tags)` Create a new histogram with the meter name and 
optional tags.
+1. `Histogram.Builder(name, tags)` Create a new histogram builder with the 
meter name and optional tags.
 1. `Histogram.tag(key: str, value)` Mark a tag key/value pair.
 1. `Histogram.minValue(value)` Set up the minimal value of this histogram, 
default is `0`.
 1. `Histogram.build()` Build a new `Histogram` which is collected and reported 
to the backend.
diff --git a/skywalking/meter/counter.py b/skywalking/meter/counter.py
index 123b9d2..1a1edec 100644
--- a/skywalking/meter/counter.py
+++ b/skywalking/meter/counter.py
@@ -50,10 +50,6 @@ class Counter(BaseMeter):
         meterdata = 
MeterData(singleValue=MeterSingleValue(name=self.get_name(), 
labels=self.transform_tags(), value=count))
         return meterdata
 
-    def mode(self, mode):
-        self.mode = mode
-        return self
-
     def get_type(self):
         return MeterType.COUNTER
 
@@ -98,3 +94,11 @@ class Counter(BaseMeter):
             return wrapper
 
         return inner
+
+    class Builder(BaseMeter.Builder):
+        def __init__(self, name: str, mode: CounterMode, tags=None):
+            self.meter = Counter(name, mode, tags)
+
+        def mode(self, mode: CounterMode):
+            self.meter.mode = mode
+            return self
diff --git a/skywalking/meter/gauge.py b/skywalking/meter/gauge.py
index b004fed..a74e957 100644
--- a/skywalking/meter/gauge.py
+++ b/skywalking/meter/gauge.py
@@ -35,3 +35,7 @@ class Gauge(BaseMeter):
 
     def get_type(self):
         return MeterType.GAUGE
+
+    class Builder(BaseMeter.Builder):
+        def __init__(self, name: str, generator, tags=None):
+            self.meter = Gauge(name, generator, tags)
diff --git a/skywalking/meter/histogram.py b/skywalking/meter/histogram.py
index 3a81cf2..5c5e5df 100644
--- a/skywalking/meter/histogram.py
+++ b/skywalking/meter/histogram.py
@@ -25,10 +25,12 @@ class Histogram(BaseMeter):
         super().__init__(name, tags)
         self.min_value = min_value
 
+        # check if a list is empty?
         # https://stackoverflow.com/a/53522/9845190
         if not steps:
             raise Exception('steps must not be empty')
 
+        # sort and deduplicate
         # https://stackoverflow.com/a/2931683/9845190
         steps = sorted(set(steps))
 
@@ -50,7 +52,7 @@ class Histogram(BaseMeter):
         left = 0
         right = len(self.buckets)
 
-        # find the first bucket greater than or equal the value
+        # find the first bucket greater than or equal to the value
         while left < right:
             mid = (left + right) // 2
             if self.buckets[mid].bucket < value:
@@ -118,3 +120,7 @@ class Histogram(BaseMeter):
             return wrapper
 
         return inner
+
+    class Builder(BaseMeter.Builder):
+        def __init__(self, name: str, steps, min_value=0, tags=None):
+            self.meter = Histogram(name, steps, min_value, tags)
diff --git a/skywalking/meter/meter.py b/skywalking/meter/meter.py
index 5eba338..f8eacd1 100644
--- a/skywalking/meter/meter.py
+++ b/skywalking/meter/meter.py
@@ -49,20 +49,20 @@ class MeterTag():
 
 
 class MeterId():
-    def __init__(self, name: str, type, tags: list) -> None:
+    def __init__(self, name: str, type, tags: tuple) -> None:
         if tags is None:
-            tags = []
+            tags = ()
 
         self.name = name
         self.type = type
-        self.tags = tags
+        self.tags = [MeterTag(key, value) for (key, value) in tags]
         self.labels = None
 
     def transform_tags(self):
         if self.labels is not None:
             return self.labels
 
-        self.labels = [Label(tag.key, tag.value) for tag in self.tags]
+        self.labels = [Label(name=tag.key, value=tag.value) for tag in 
self.tags]
         return self.labels
 
     def get_name(self):
@@ -101,14 +101,22 @@ class BaseMeter(ABC):
     def transform_tags(self):
         return self.get_id().transform_tags()
 
-    def tag(self, name: str, value):
-        self.meterId.get_tags().append(MeterTag(name, value))
-        return self
-
-    def build(self):
-        self.meterId.get_tags().sort()
-        BaseMeter.meter_service.register(self)
-
     @abstractmethod
     def get_type(self):
         pass
+
+    class Builder(ABC):
+        @abstractmethod
+        def __init__(self, name: str, tags=None):
+            # Derived Builder should instantiate its corresponding meter here.
+            # self.meter = BaseMeter(name, tags)
+            pass
+
+        def tag(self, name: str, value):
+            self.meter.meterId.get_tags().append(MeterTag(name, value))
+            return self
+
+        def build(self):
+            self.meter.meterId.get_tags().sort()
+            BaseMeter.meter_service.register(self.meter)
+            return self.meter
diff --git a/tests/unit/test_meter.py b/tests/unit/test_meter.py
index 1569fbf..4447abc 100644
--- a/tests/unit/test_meter.py
+++ b/tests/unit/test_meter.py
@@ -52,8 +52,9 @@ tolerance = 5e-2
 
 class TestMeter(unittest.TestCase):
     def test_counter(self):
-        c = Counter('c1', CounterMode.INCREMENT)
-        c.build()
+        builder = Counter.Builder('c1', CounterMode.INCREMENT, (('k1', 'v1'), 
('k2', 'v2')))
+        builder.tag('k3', 'v3')
+        c = builder.build()
 
         @Counter.increase(name='c1')
         def increase_by_one():
@@ -68,8 +69,8 @@ class TestMeter(unittest.TestCase):
             self.assertEqual(i, meterdata.singleValue.value)
 
     def test_counter_with_satement(self):
-        c = Counter('c2', CounterMode.INCREMENT)
-        c.build()
+        builder = Counter.Builder('c2', CounterMode.INCREMENT)
+        c = builder.build()
 
         ls = [i / 10 for i in range(10)]
         random.shuffle(ls)
@@ -86,8 +87,8 @@ class TestMeter(unittest.TestCase):
 
 
     def test_counter_increase_decarator(self):
-        c = Counter('c3', CounterMode.INCREMENT)
-        c.build()
+        builder = Counter.Builder('c3', CounterMode.INCREMENT)
+        c = builder.build()
 
         @Counter.increase(name='c3', num=2)
         def counter_decorator_test():
@@ -101,8 +102,8 @@ class TestMeter(unittest.TestCase):
             self.assertEqual(i * 2, meterdata.singleValue.value)
 
     def test_counter_timer_decarator(self):
-        c = Counter('c4', CounterMode.INCREMENT)
-        c.build()
+        builder = Counter.Builder('c4', CounterMode.INCREMENT)
+        c = builder.build()
 
         ls = [i / 10 for i in range(10)]
 
@@ -121,8 +122,8 @@ class TestMeter(unittest.TestCase):
                 self.assertLessEqual(abs(total - meterdata.singleValue.value), 
tolerance)
 
     def test_histogram(self):
-        h = Histogram('h1', list(range(0, 10)))
-        h.build()
+        builder = Histogram.Builder('h1', list(range(0, 10)))
+        h = builder.build()
 
         for repeat in range(1, 10):
             ls = list(range(1, 10))
@@ -135,8 +136,8 @@ class TestMeter(unittest.TestCase):
                 self.assertEqual(repeat, meterdata.histogram.values[i - 
1].count)
 
     def test_histogram_timer_decarator(self):
-        h = Histogram('h2', [i / 10 for i in range(10)])
-        h.build()
+        builder = Histogram.Builder('h2', [i / 10 for i in range(10)])
+        h = builder.build()
 
         ls = [i / 10 for i in range(10)]
 
@@ -153,8 +154,8 @@ class TestMeter(unittest.TestCase):
                 self.assertEqual(repeat, meterdata.histogram.values[idx].count)
 
     def test_histogram_with_satement(self):
-        h = Histogram('h3', [i / 10 for i in range(10)])
-        h.build()
+        builder = Histogram.Builder('h3', [i / 10 for i in range(10)])
+        h = builder.build()
 
         ls = [i / 10 for i in range(10)]
 
@@ -171,8 +172,8 @@ class TestMeter(unittest.TestCase):
     def test_gauge(self):
         ls = list(range(1, 10))
         random.shuffle(ls)
-        g = Gauge('g1', iter(ls))
-        g.build()
+        builder = Gauge.Builder('g1', iter(ls))
+        g = builder.build()
 
         for i in ls:
             meterdata = meter_service.transform(g)

Reply via email to