Merge "Improve VMs spawning for OpenStack"
[yardstick.git] / third_party / influxdb / influxdb_line_protocol.py
1 # The MIT License (MIT)
2
3 # Copyright (c) 2013 InfluxDB
4
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in
8 # the Software without restriction, including without limitation the rights to
9 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 # of the Software, and to permit persons to whom the Software is furnished to
11 # do so, subject to the following conditions:
12
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 # SOFTWARE.
23
24 # yardstick comment: this file is a modified copy of
25 # influxdb-python/influxdb/line_protocol.py
26
27 from __future__ import absolute_import
28 from __future__ import unicode_literals
29
30 from copy import copy
31
32 from oslo_utils import encodeutils
33 from six import binary_type, text_type, integer_types
34
35
36 def _escape_tag(tag):
37     tag = _get_unicode(tag, force=True)
38     return tag.replace(
39         "\\", "\\\\"
40     ).replace(
41         " ", "\\ "
42     ).replace(
43         ",", "\\,"
44     ).replace(
45         "=", "\\="
46     )
47
48
49 def _escape_value(value):
50     value = _get_unicode(value)
51     if isinstance(value, text_type) and value != '':
52         return "\"{}\"".format(
53             value.replace(
54                 "\"", "\\\""
55             ).replace(
56                 "\n", "\\n"
57             )
58         )
59     elif isinstance(value, integer_types) and not isinstance(value, bool):
60         return str(value) + 'i'
61     else:
62         return str(value)
63
64
65 def _get_unicode(data, force=False):
66     """
67     Try to return a text aka unicode object from the given data.
68     """
69     if isinstance(data, binary_type):
70         return encodeutils.safe_decode(data, 'utf-8')
71     elif data is None:
72         return ''
73     elif force:
74         return str(data)
75     else:
76         return data
77
78
79 def make_lines(data):
80     """
81     Extracts the points from the given dict and returns a Unicode string
82     matching the line protocol introduced in InfluxDB 0.9.0.
83
84     line protocol format:
85         <measurement>[,<tag-key>=<tag-value>...] <field-key>=<field-value>\
86             [,<field2-key>=<field2-value>...] [unix-nano-timestamp]
87
88     Ref:
89         https://influxdb.com/docs/v0.9/write_protocols/write_syntax.html
90         https://influxdb.com/docs/v0.9/write_protocols/line.html
91     """
92     lines = []
93     static_tags = data.get('tags', None)
94     for point in data['points']:
95         elements = []
96
97         # add measurement name
98         measurement = _escape_tag(_get_unicode(
99             point.get('measurement', data.get('measurement'))
100         ))
101         key_values = [measurement]
102
103         # add tags
104         if static_tags is None:
105             tags = point.get('tags', {})
106         else:
107             tags = copy(static_tags)
108             tags.update(point.get('tags', {}))
109
110         # tags should be sorted client-side to take load off server
111         for tag_key in sorted(tags.keys()):
112             key = _escape_tag(tag_key)
113             value = _escape_tag(tags[tag_key])
114
115             if key != '' and value != '':
116                 key_values.append("{key}={value}".format(key=key, value=value))
117         key_values = ','.join(key_values)
118         elements.append(key_values)
119
120         # add fields
121         field_values = []
122         for field_key in sorted(point['fields'].keys()):
123             key = _escape_tag(field_key)
124             value = _escape_value(point['fields'][field_key])
125             if key != '' and value != '':
126                 field_values.append("{key}={value}".format(
127                     key=key,
128                     value=value
129                 ))
130         field_values = ','.join(field_values)
131         elements.append(field_values)
132
133         # add timestamp
134         if 'time' in point:
135             elements.append(point['time'])
136
137         line = ' '.join(elements)
138         lines.append(line)
139     lines = '\n'.join(lines)
140     return lines + '\n'