summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Carter <kcarter@linux.com>2017-03-19 09:03:06 -0500
committerMajor Hayden <major@mhtx.net>2017-03-19 09:03:06 -0500
commita61786d4e1e030cd6f8b7d8c4f326d92143cb6a3 (patch)
tree5db10d735f827bf8a91096df44b2fbc8064c979c
parent775f034a78ccc7f4aaf8810b1fd14fdc7027e227 (diff)
added rackspace maas format (#28)
Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
-rwxr-xr-xmonitorstack/cli.py5
-rw-r--r--monitorstack/common/formatters.py83
-rw-r--r--tests/test_formatters.py111
3 files changed, 190 insertions, 9 deletions
diff --git a/monitorstack/cli.py b/monitorstack/cli.py
index 06ab0de..324c577 100755
--- a/monitorstack/cli.py
+++ b/monitorstack/cli.py
@@ -82,7 +82,8 @@ class MonitorStackCLI(click.MultiCommand):
82VALID_OUTPUT_FORMATS = [ 82VALID_OUTPUT_FORMATS = [
83 'json', 83 'json',
84 'line', 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):
107def process_result(result, output_format, verbose): 108def process_result(result, output_format, verbose):
108 """Render the output into the proper format.""" 109 """Render the output into the proper format."""
109 module_name = 'monitorstack.common.formatters' 110 module_name = 'monitorstack.common.formatters'
110 method_name = 'write_{}'.format(output_format) 111 method_name = 'write_{}'.format(output_format.replace('-', '_'))
111 output_formatter = getattr( 112 output_formatter = getattr(
112 importlib.import_module(module_name), 113 importlib.import_module(module_name),
113 method_name 114 method_name
diff --git a/monitorstack/common/formatters.py b/monitorstack/common/formatters.py
index 6f5ea8f..6737905 100644
--- a/monitorstack/common/formatters.py
+++ b/monitorstack/common/formatters.py
@@ -12,6 +12,7 @@
12# See the License for the specific language governing permissions and 12# See the License for the specific language governing permissions and
13# limitations under the License. 13# limitations under the License.
14"""Output methods.""" 14"""Output methods."""
15
15import json 16import json
16import time 17import time
17 18
@@ -38,18 +39,62 @@ def _current_time():
38 return int(time.time() * 1000000000) 39 return int(time.time() * 1000000000)
39 40
40 41
42def _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
41def _telegraf_line_format(sets, quote=False): 92def _telegraf_line_format(sets, quote=False):
42 """Return a comma separated string.""" 93 """Return a comma separated string."""
43 store = list() 94 store = list()
44 for k, v in sets.items(): 95 for k, v in sets.items():
45 k = k.replace(' ', '_') 96 k = k.replace(' ', '_')
46 for v_type in [int, float]: 97 v, _ = _get_value_types(value=v)
47 try:
48 v = v_type(v)
49 except ValueError:
50 pass # v was not a int, float, or long
51 else:
52 break
53 if not isinstance(v, (int, float, bool)) and quote: 98 if not isinstance(v, (int, float, bool)) and quote:
54 store.append('{}="{}"'.format(k, v)) 99 store.append('{}="{}"'.format(k, v))
55 else: 100 else:
@@ -72,3 +117,27 @@ def write_telegraf(result):
72 click.echo(' '.join(resultant)) 117 click.echo(' '.join(resultant))
73 118
74 return True 119 return True
120
121
122def 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
diff --git a/tests/test_formatters.py b/tests/test_formatters.py
index e25c53b..3cdf785 100644
--- a/tests/test_formatters.py
+++ b/tests/test_formatters.py
@@ -28,6 +28,40 @@ SAMPLE_RESULT = {
28 } 28 }
29} 29}
30 30
31SAMPLE_RESULT_ERROR = {
32 'exit_code': 1,
33 'message': 'uptime failed',
34 'measurement_name': 'system_uptime',
35 'meta': {},
36 'variables': {}
37}
38
39SAMPLE_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
52SAMPLE_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
31SAMPLE_RESULT_NO_META = { 65SAMPLE_RESULT_NO_META = {
32 'exit_code': 0, 66 'exit_code': 0,
33 'message': 'uptime is ok', 67 'message': 'uptime is ok',
@@ -56,6 +90,54 @@ class TestFormatters(object):
56 assert isinstance(result, int) 90 assert isinstance(result, int)
57 assert result > 0 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 def test_write_json(self, capsys): 141 def test_write_json(self, capsys):
60 """Test write_json() module.""" 142 """Test write_json() module."""
61 formatters.write_json(SAMPLE_RESULT) 143 formatters.write_json(SAMPLE_RESULT)
@@ -95,3 +177,32 @@ class TestFormatters(object):
95 assert isinstance(result, str) 177 assert isinstance(result, str)
96 assert 'othervar=3' in result 178 assert 'othervar=3' in result
97 assert 'platform="example_platform"' in result 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]