Browse Source

added rackspace maas format (#28)

Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
changes/49/448649/1
Kevin Carter 2 years ago
parent
commit
a61786d4e1
3 changed files with 190 additions and 9 deletions
  1. 3
    2
      monitorstack/cli.py
  2. 76
    7
      monitorstack/common/formatters.py
  3. 111
    0
      tests/test_formatters.py

+ 3
- 2
monitorstack/cli.py View File

@@ -82,7 +82,8 @@ class MonitorStackCLI(click.MultiCommand):
82 82
 VALID_OUTPUT_FORMATS = [
83 83
     'json',
84 84
     'line',
85
-    'telegraf'
85
+    'telegraf',
86
+    'rax-maas'
86 87
 ]
87 88
 
88 89
 
@@ -107,7 +108,7 @@ def cli(ctx, output_format, verbose):
107 108
 def process_result(result, output_format, verbose):
108 109
     """Render the output into the proper format."""
109 110
     module_name = 'monitorstack.common.formatters'
110
-    method_name = 'write_{}'.format(output_format)
111
+    method_name = 'write_{}'.format(output_format.replace('-', '_'))
111 112
     output_formatter = getattr(
112 113
         importlib.import_module(module_name),
113 114
         method_name

+ 76
- 7
monitorstack/common/formatters.py View File

@@ -12,6 +12,7 @@
12 12
 # See the License for the specific language governing permissions and
13 13
 # limitations under the License.
14 14
 """Output methods."""
15
+
15 16
 import json
16 17
 import time
17 18
 
@@ -38,18 +39,62 @@ def _current_time():
38 39
     return int(time.time() * 1000000000)
39 40
 
40 41
 
42
+def _get_value_types(value, measurement_type=None):
43
+    """Return the value and the measurement type.
44
+
45
+    This method will evaluate a given value and cast it to the
46
+    appropriate type. If the parameter `measurement_type` is
47
+    not provided the method will assign the type based on the
48
+    key set in the types list.
49
+
50
+    :param value: item to evaluate.
51
+    :param measurement_type: name of the measurement
52
+    """
53
+    def _check_value(c_type, c_value):
54
+        try:
55
+            c_value = c_type(c_value)
56
+        except ValueError:
57
+            return False, c_value
58
+        else:
59
+            return True, c_value
60
+
61
+    success = False
62
+    if isinstance(value, str) and '.' in value:
63
+        success, value = _check_value(
64
+            c_type=float,
65
+            c_value=value
66
+        )
67
+
68
+    elif isinstance(value, float):
69
+        success = True
70
+
71
+    if success:
72
+        _measurement_type = 'float'
73
+    else:
74
+        _, value = _check_value(
75
+            c_type=int,
76
+            c_value=value
77
+        )
78
+        if isinstance(value, int):
79
+            if value > 2147483647:
80
+                _measurement_type = 'int64'
81
+            else:
82
+                _measurement_type = 'int32'
83
+        else:
84
+            _measurement_type = 'string'
85
+
86
+    if not measurement_type:
87
+        measurement_type = _measurement_type
88
+
89
+    return value, measurement_type
90
+
91
+
41 92
 def _telegraf_line_format(sets, quote=False):
42 93
     """Return a comma separated string."""
43 94
     store = list()
44 95
     for k, v in sets.items():
45 96
         k = k.replace(' ', '_')
46
-        for v_type in [int, float]:
47
-            try:
48
-                v = v_type(v)
49
-            except ValueError:
50
-                pass  # v was not a int, float, or long
51
-            else:
52
-                break
97
+        v, _ = _get_value_types(value=v)
53 98
         if not isinstance(v, (int, float, bool)) and quote:
54 99
             store.append('{}="{}"'.format(k, v))
55 100
         else:
@@ -72,3 +117,27 @@ def write_telegraf(result):
72 117
     click.echo(' '.join(resultant))
73 118
 
74 119
     return True
120
+
121
+
122
+def write_rax_maas(result):
123
+    """Output in Rackspace Monitoring as a Service format."""
124
+    status = ['status']
125
+    if result['exit_code'] == 0:
126
+        status.append('okay')
127
+    else:
128
+        status.append('error')
129
+
130
+    status.append(result['message'])
131
+    click.echo(' '.join(status))
132
+
133
+    for key, value in result['variables'].items():
134
+        value, measurement_type = _get_value_types(
135
+            value=value,
136
+            measurement_type=result.get('measurement_type')
137
+        )
138
+        metric = ['metric', key, measurement_type, str(value)]
139
+        if 'measurement_units' in result:
140
+            metric.append(result['measurement_units'])
141
+        click.echo(' '.join(metric))
142
+
143
+    return True

+ 111
- 0
tests/test_formatters.py View File

@@ -28,6 +28,40 @@ SAMPLE_RESULT = {
28 28
     }
29 29
 }
30 30
 
31
+SAMPLE_RESULT_ERROR = {
32
+    'exit_code': 1,
33
+    'message': 'uptime failed',
34
+    'measurement_name': 'system_uptime',
35
+    'meta': {},
36
+    'variables': {}
37
+}
38
+
39
+SAMPLE_RESULT_MEASUREMENT_TYPE = {
40
+    'exit_code': 0,
41
+    'message': 'uptime is ok',
42
+    'measurement_name': 'system_uptime',
43
+    'measurement_type': 'testType',
44
+    'meta': {
45
+        'platform': 'example_platform',
46
+    },
47
+    'variables': {
48
+        'uptime': '29587.75'
49
+    }
50
+}
51
+
52
+SAMPLE_RESULT_MEASUREMENT_UNITS = {
53
+    'exit_code': 0,
54
+    'message': 'uptime is ok',
55
+    'measurement_name': 'system_uptime',
56
+    'measurement_units': 'testUnits',
57
+    'meta': {
58
+        'platform': 'example_platform',
59
+    },
60
+    'variables': {
61
+        'uptime': '29587.75'
62
+    }
63
+}
64
+
31 65
 SAMPLE_RESULT_NO_META = {
32 66
     'exit_code': 0,
33 67
     'message': 'uptime is ok',
@@ -56,6 +90,54 @@ class TestFormatters(object):
56 90
         assert isinstance(result, int)
57 91
         assert result > 0
58 92
 
93
+    def test__get_value_types_int32(self):
94
+        """Test _get_value_types() with int."""
95
+        value, m_type = formatters._get_value_types(1)
96
+        assert value == 1
97
+        assert m_type == 'int32'
98
+
99
+    def test__get_value_types_int32_str(self):
100
+        """Test _get_value_types() with int."""
101
+        value, m_type = formatters._get_value_types('1')
102
+        assert value == 1
103
+        assert m_type == 'int32'
104
+
105
+    def test__get_value_types_int64(self):
106
+        """Test _get_value_types() with int."""
107
+        value, m_type = formatters._get_value_types(9999999999)
108
+        assert value == 9999999999
109
+        assert m_type == 'int64'
110
+
111
+    def test__get_value_types_int64_str(self):
112
+        """Test _get_value_types() with int."""
113
+        value, m_type = formatters._get_value_types('9999999999')
114
+        assert value == 9999999999
115
+        assert m_type == 'int64'
116
+
117
+    def test__get_value_types_float(self):
118
+        """Test _get_value_types() with float."""
119
+        value, m_type = formatters._get_value_types(1.1)
120
+        assert value == 1.1
121
+        assert m_type == 'float'
122
+
123
+    def test__get_value_types_float_str(self):
124
+        """Test _get_value_types() with float."""
125
+        value, m_type = formatters._get_value_types('1.1')
126
+        assert value == 1.1
127
+        assert m_type == 'float'
128
+
129
+    def test__get_value_types_set_m_type(self):
130
+        """Test _get_value_types() with float."""
131
+        value, m_type = formatters._get_value_types('1.1', 'double')
132
+        assert value == 1.1
133
+        assert m_type == 'double'
134
+
135
+    def test__get_value_types_string(self):
136
+        """Test _get_value_types() with str."""
137
+        value, m_type = formatters._get_value_types('TestString')
138
+        assert value == 'TestString'
139
+        assert m_type == 'string'
140
+
59 141
     def test_write_json(self, capsys):
60 142
         """Test write_json() module."""
61 143
         formatters.write_json(SAMPLE_RESULT)
@@ -95,3 +177,32 @@ class TestFormatters(object):
95 177
         assert isinstance(result, str)
96 178
         assert 'othervar=3' in result
97 179
         assert 'platform="example_platform"' in result
180
+
181
+    def test_write_rax_maas(self, capsys):
182
+        """Test write_telegraf() module."""
183
+        formatters.write_rax_maas(SAMPLE_RESULT)
184
+        out, err = capsys.readouterr()
185
+        assert SAMPLE_RESULT['message'] in out
186
+        assert 'metric uptime float 29587.75' in out
187
+
188
+    def test_write_rax_maas_with_types(self, capsys):
189
+        """Test write_telegraf() module."""
190
+        formatters.write_rax_maas(SAMPLE_RESULT_MEASUREMENT_TYPE)
191
+        out, err = capsys.readouterr()
192
+        assert SAMPLE_RESULT['message'] in out
193
+        assert 'metric uptime testType 29587.75' in out
194
+
195
+    def test_write_rax_maas_with_units(self, capsys):
196
+        """Test write_telegraf() module."""
197
+        formatters.write_rax_maas(SAMPLE_RESULT_MEASUREMENT_UNITS)
198
+        out, err = capsys.readouterr()
199
+        out_split = out.splitlines()
200
+        assert [i for i in out_split if SAMPLE_RESULT['message'] in i]
201
+        assert 'metric uptime float 29587.75 testUnits' in out_split
202
+
203
+    def test_write_rax_maas_with_error(self, capsys):
204
+        """Test write_telegraf() module."""
205
+        formatters.write_rax_maas(SAMPLE_RESULT_ERROR)
206
+        out, err = capsys.readouterr()
207
+        out_split = out.splitlines()
208
+        assert [i for i in out_split if 'status error' in i]

Loading…
Cancel
Save