Skip to content

Commit 59a992d

Browse files
committed
Changes some method names, updates the documentation, adds ability to change the tenant and query for metric aggregates
1 parent f2ab735 commit 59a992d

4 files changed

Lines changed: 115 additions & 113 deletions

File tree

README.md

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This repository includes the necessary Python client libraries to access Hawkula
55

66
## Introduction
77

8-
Python client to access Hawkular-Metrics, an abstraction to invoke REST-methods on the server endpoint using urllib2. No external dependencies, works with Python 2.7.x and Python 3.4.x (tested with the Python 3.4.2, might work with newer versions also)
8+
Python client to access Hawkular-Metrics, an abstraction to invoke REST-methods on the server endpoint using urllib2. No external dependencies, works with Python 2.7.x (tested on 2.7.5/2.7.6 and 2.7.10) and Python 3.4.x (tested with the Python 3.4.2, might work with newer versions also)
99

1010
## License and copyright
1111

@@ -28,98 +28,109 @@ Python client to access Hawkular-Metrics, an abstraction to invoke REST-methods
2828

2929
## Installation
3030

31-
To install, run ``python setup.py install``
31+
To install, run ``python setup.py install`` if you installed from source code, or ``pip install hawkular-client`` if using pip.
3232

3333
## Usage
3434

35-
To use hawkular-client-python in your own program, after installation import from hawkular the class HawkularMetricsClient and instantiate it. It accepts parameters tenant_id, hostname and port. After this, push dicts with keys id, timestamp and value with put or use assistant method create to send events.
35+
To use hawkular-client-python in your own program, after installation import from hawkular the class HawkularMetricsClient and instantiate it. After this, push dicts with keys id, timestamp and value with put or use assistant method create to send events. pydoc gives the list of allowed parameters for each function.
3636

3737
Timestamps should be in the milliseconds after epoch and numeric values should be float. The client provides a method to request current time in milliseconds, ``time_millis()``
3838

39-
See metrics_test.py for more detailed examples. The tests target a running docker instance of Hawkular Kettle by default (change setUp() to override).
39+
See metrics_test.py for more detailed examples and [Hawkular-Metrics documentation](http://www.hawkular.org/docs/components/metrics/index.html) for more detailed explanation of available features.
4040

4141
### General
4242

43-
When a method wants a metric_type one can use the shortcuts of MetricType.Gauge or MetricType.Availability. For availability values, one can use Availability.Up and Availability.Down to simplify usage.
43+
When a method wants a metric_type one can use the shortcuts of from MetricType class (Gauge, Availability and Counter). For availability values, one can use values Availability.Up and Availability.Down to simplify usage.
44+
45+
To instantiate the client, use HawkularMetricsClient() method. It requires something given as tenant_id, even if the tenant does not exists yet (it is not auto-created, you have to call ``create_tenant(tenant_id)`` to create it). To change the target tenant_id, use ``tenant(tenant_id)``
4446

4547
```python
46-
>>> from hawkular.metrics import *
47-
>>> client = HawkularMetricsClient(tenant_id='doc', port=8081)
48+
>>> from hawkular.metrics import HawkularMetricsClient, MetricType
49+
>>> client = HawkularMetricsClient(tenant_id='python_test')
4850
```
4951

5052
### Creating and modifying metric definitions
5153

52-
While creating a metric definition is not required to use them, it is possible to define a custom data retention times as well as tags for each metric. To create a metric, use method create_metric_definition(metric_id, metric_type, **tags). There are assistant methods create_numeric_definition(metric_id, **tags) and create_availability_definition(metric_id, **tags) which bypass the need for MetricType definition. The only reserved keyword for tags is dataRetention, which will change the dataRetention time, other tags are used for user's metadata.
54+
While creating a metric definition is not required, it is recommended to avoid duplicate metric_ids, which could cause silent data overwriting. It is possible to define a custom data retention times as well as tags for each metric. To create a metric, use method ``create_metric_definition(metric_id, metric_type, **tags)`` The only reserved keyword for tags is dataRetention, which will change the dataRetention time, other tag names are used for user's metadata.
5355

5456
Example:
5557

5658
```python
57-
>>> client.create_numeric_definition('example.metric.1', dataRetention=90, units='bytes', hostname='localhost')
59+
>>> client.create_metric_definition(MetricType.Gauge, 'example.doc.1', units='bytes', env='test')
5860
True
59-
>>> client.query_definitions(metrics.MetricType.Gauge)
60-
[{u'tags': {u'units': u'bytes', u'hostname': u'localhost'}, u'id': u'example.metric.1', u'dataRetention': 90, u'tenantId': u'doc'}]
61+
>>> client.query_metric_definitions(MetricType.Gauge)
62+
[{'type': 'gauge', 'id': 'example.doc.1', 'tags': {'units': 'bytes', 'env': 'test'}, 'tenantId': 'python_test', 'dataRetention': 7}]
6163
```
6264

6365
### Modifying metric definition tags
6466

65-
One powerful feature of Hawkular-Metrics is the tagging feature that allows one to define descriptive metadata for any metric. Tags can be added when creating a metric definition (see above), but also modified later.
67+
One powerful feature of Hawkular-Metrics is the tagging feature that allows one to define descriptive metadata for any metric. Tags can be added when creating a metric definition (see above), but also modified later. By tagging the definitions, you can search for matching definitions with the tag query language.
6668

6769
Example:
6870

6971
```python
70-
>>> client.create_numeric_definition('example.metric.1', dataRetention=90, units='bytes', hostname='localhost')
71-
>>> client.query_metric_tags(MetricType.Gauge, 'example.metric.1')
72-
{u'units': u'bytes', u'hostname': u'localhost'}
73-
>>> client.delete_metric_tags(MetricType.Gauge, 'example.metric.1', units='bytes')
74-
>>> client.query_metric_tags(MetricType.Gauge, 'example.metric.1')
75-
{u'hostname': u'localhost'}
76-
>>> client.update_metric_tags(MetricType.Gauge, 'example.metric.1', hostname='machine1', env='test')
77-
>>> client.query_metric_tags(MetricType.Gauge, 'example.metric.1')
78-
{u'hostname': u'machine1', u'env': u'test'}
72+
>>> client.create_metric_definition(MetricType.Gauge, 'example.doc.2', units='bytes', env='test', hostname='testenv01')
73+
>>> client.query_metric_tags(MetricType.Gauge, 'example.doc.2')
74+
{'units': 'bytes', 'hostname': 'testenv01', 'env': 'test'}
7975
```
8076

81-
### Pushing new values
77+
To search all the metric definitions with a given tags and tag values, use the ``query_definitions()``
8278

83-
All the methods that allow pushing values can accept both availability status as well as numeric values. It is possible to push multiple metrics with multiple values per metric in one call to the Hawkular-Metrics. However for convenience, methods which will push just one value for one metric is also provided. To push availability values, use MetricType.Availability and values Availability.Up and Availability.Down, otherwise the syntax is equal.
79+
```python
80+
>>> client.query_metric_definitions(MetricType.Gauge, hostname='testenv.*')
81+
[{'type': 'gauge', 'id': 'example.doc.2', 'tags': {'units': 'bytes', 'hostname': 'testenv01', 'env': 'test'}, 'tenantId': 'python_test', 'dataRetention': 7}]
82+
```
8483

85-
Example pushing a single value:
84+
It is also possible to query all the available tag values, in case you want to list for example the hostnames that have metrics information gathered.
8685

8786
```python
88-
datapoint = create_datapoint(float(4.35), time_millis())
89-
metric = create_metric(MetricType.Gauge, 'example.metric.1', datapoint)
90-
client.put(metric)
87+
>>> client.query_tag_values(hostname='*')
88+
{'hostname': ['testenv01', 'prodenv01']}
9189
```
9290

93-
And a shortcut method for the above:
91+
### Pushing new values
92+
93+
All the methods that allow pushing values can accept both availability status as well as float values. It is possible to push multiple metrics with multiple values per metric in one call to the Hawkular-Metrics. However for convenience, a method which will push just one value for one metric is also provided. To push availability values, use MetricType.Availability and values Availability.Up and Availability.Down, otherwise the syntax is equal.
94+
95+
``create_datapoint(value)`` and ``create_metric(metric_type, metric_id, datapoints)`` return the necessary structures requested by the multi-functions.
96+
97+
Example pushing a multiple values:
9498

9599
```python
96-
client.push(MetricType.Gauge, 'example.metric.1', float(4.35))
100+
>>> from hawkular.metrics import create_datapoint, create_metric, time_millis
101+
>>> datapoint = create_datapoint(float(4.35), time_millis())
102+
>>> datapoint2 = create_datapoint(float(4.42), time_millis() + 10)
103+
>>> metric = create_metric(MetricType.Gauge, 'example.doc.1', [datapoint, datapoint2])
104+
>>> client.put(metric)
97105
```
98106

99-
Example pushing multiple values for the same metric (with given timestamp and without):
107+
And a shortcut method to push just a single value with automatically generated timestamp:
100108

101109
```python
102-
>>> v1 = create_datapoint(float(2.345)) # Timestamp is autogenerated
103-
>>> v2 = create_datapoint(float(3.45), 1429711362289) # Timestamp is given
104-
>>> m = create_metric(MetricType.Gauge, 'example.metric.2', [v1, v2])
105-
>>> client.put(m)
106-
>>> client.query_single_numeric('example.metric.2')
107-
[{u'timestamp': 1429711362289, u'value': 3.45}, {u'timestamp': 1429711311895, u'value': 2.345}]
110+
>>> client.push(MetricType.Gauge, 'example.doc.1', float(4.24))
108111
```
109112

110113
To push multiple metrics with multiple values per metric, see metrics_test.py and method ``test_add_multi_metrics_and_datapoints()``.
111114

112115
### Querying metric values
113116

114-
Querying metrics is limited to just metric_id querying now with given search_options. Search for tagged data is coming up later. The supported parameters are ``start``, ``end``, ``buckets``, ``bucketDuration`` and ``distinct``. The returned data structure will change depending on the given parameters.
117+
Querying metrics and its raw values happens through the method ``query_metric(metric_type, metric_id, **query_options)``. Available options are listed in the Hawkular-Metrics documentation. To query for aggregated values, use the method ``query_metric_stats(metric_type, metric_id, **query_options)``
118+
119+
Example querying for raw values:
120+
121+
```python
122+
>>> client.query_metric(MetricType.Gauge, 'example.doc.1')
123+
[{'value': 4.24, 'timestamp': 1462363124102}, {'value': 4.42, 'timestamp': 1462363032249}, {'value': 4.35, 'timestamp': 1462362981464}]
124+
>>> client.query_metric(MetricType.Gauge, 'example.doc.1', start=1462363032249)
125+
[{'value': 4.24, 'timestamp': 1462363124102}, {'value': 4.42, 'timestamp': 1462363032249}]
126+
```
127+
128+
For aggregated metrics:
115129

116130
```python
117-
>>> c.query_metric(MetricType.Gauge, 'test.query.numeric.1')
118-
[{u'timestamp': 1429816731689, u'value': 1.45}, {u'timestamp': 1429816729689, u'value': 2.0}]
119-
>>> c.query_metric(MetricType.Gauge, 'test.query.numeric.1', start=1429816731689)
120-
[{u'timestamp': 1429816731689, u'value': 1.45}]
121-
>>> c.query_metric(MetricType.Gauge, 'test.query.numeric.1', buckets=1)
122-
[{u'end': 1429816997651, u'min': 1.45, u'max': 2.0, u'median': 1.725, u'value': u'NaN', u'start': 1429788197651, u'avg': 1.725, u'empty': False, u'percentile95th': 2.0}]
131+
>>> client.query_metric_stats(MetricType.Gauge, 'example.doc.1', buckets=2, percentiles='90.0,95.0')
132+
[{'empty': True, 'start': 1462334779765, 'end': 1462349179765}, {'empty': False, 'avg': 4.336666666666667, 'start': 1462349179765, 'min': 4.24, 'samples': 3, 'sum': 13.01, 'max': 4.42, 'end': 1462363579765, 'median': 4.35, 'percentiles': [{'value': 4.35, 'quantile': 0.9}, {'value': 4.35, 'quantile': 0.95}]}]
133+
>>>
123134
```
124135

125136
## Method documentation

hawkular/metrics.py

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class MetricType:
3636
Availability = 'availability'
3737
Counter = 'counters'
3838
Rate = 'rate'
39+
_Metrics = 'metrics'
3940

4041
@staticmethod
4142
def short(metric_type):
@@ -72,7 +73,7 @@ def http_response(self, request, response):
7273
class HawkularMetricsClient:
7374
"""
7475
Creates new client for Hawkular-Metrics. As tenant_id, give intended tenant_id, even if it's not
75-
created yet. Use one instance of HawkularMetricsClient for each tenant.
76+
created yet. To change the instance's tenant_id, use tenant(tenant_id) method
7677
"""
7778
def __init__(self,
7879
tenant_id,
@@ -116,7 +117,10 @@ def _clean_metric_id(metric_id):
116117
def _get_base_url(self):
117118
return "{0}://{1}:{2}/{3}/".format(self.scheme, self.host, str(self.port), self.path)
118119

119-
def _get_url(self, metric_type):
120+
def _get_url(self, metric_type=None):
121+
if metric_type is None:
122+
metric_type = MetricType._Metrics
123+
120124
return self._get_base_url() + '{0}'.format(metric_type)
121125

122126
def _get_metrics_single_url(self, metric_type, metric_id):
@@ -228,6 +232,9 @@ def _isfloat(value):
228232
External methods
229233
"""
230234

235+
def tenant(self, tenant_id):
236+
self.tenant_id = tenant_id
237+
231238
"""
232239
Instance methods
233240
"""
@@ -254,42 +261,32 @@ def put(self, data):
254261
for l in r:
255262
self._post(self._get_metrics_raw_url(self._get_url(l)), r[l])
256263

257-
def push(self, metric_type, metric_id, value, timestamp=None, **tags):
264+
def push(self, metric_type, metric_id, value, timestamp=None):
258265
"""
259266
Pushes a single metric_id, datapoint combination to the server.
260267
261268
This method is an assistant method for the put method by removing the need to
262269
create data structures first.
263270
"""
264-
item = create_metric(metric_type, metric_id, create_datapoint(value, timestamp, **tags))
271+
item = create_metric(metric_type, metric_id, create_datapoint(value, timestamp))
265272
self.put(item)
266273

267-
def query_metric(self, metric_type, metric_id, **search_options):
274+
def query_metric(self, metric_type, metric_id, **query_options):
268275
"""
269-
Query for metrics from the server.
270-
271-
Supported search options are [optional]: start, end
272-
273-
Use methods query_single_gauge and query_single_availability for simple access
276+
Query for metrics from the server. For possible query_options, see the Hawkular-Metrics documentation.
274277
"""
275278
return self._get(
276279
self._get_metrics_raw_url(
277280
self._get_metrics_single_url(metric_type, metric_id)),
278-
**search_options)
281+
**query_options)
279282

280-
def query_single_gauge(self, metric_id, **search_options):
281-
"""
282-
See query_metric
283-
"""
284-
return self.query_metric(MetricType.Gauge, metric_id, **search_options)
285-
286-
def query_single_availability(self, metric_id, **search_options):
287-
"""
288-
See query_metric
289-
"""
290-
return self.query_metric(MetricType.Availability, metric_id, **search_options)
283+
def query_metric_stats(self, metric_type, metric_id, **query_options):
284+
return self._get(
285+
self._get_metrics_stats_url(
286+
self._get_metrics_single_url(metric_type, metric_id)),
287+
**query_options)
291288

292-
def query_definitions(self, metric_type=None, id_filter=None, **tags):
289+
def query_metric_definitions(self, metric_type=None, id_filter=None, **tags):
293290
"""
294291
Query available metric definitions. Available query options are id_filter for id filtering and tags (dict) as tag based query.
295292
Tags filtering is required for the id filtering to work.
@@ -305,26 +302,21 @@ def query_definitions(self, metric_type=None, id_filter=None, **tags):
305302
if len(tags) > 0:
306303
params['tags'] = self._transform_tags(**tags)
307304

308-
return self._get(self._get_url('metrics'), **params)
305+
return self._get(self._get_url(), **params)
309306

310-
def query_tagvalues(self, metric_type=None, **tags):
307+
def query_tag_values(self, metric_type=None, **tags):
311308
"""
312-
Query for possible tag values.
309+
Query for possible tag values. **tags is a dict which has tagname as key and regexp tagvalue as value. See Hawkular-Metrics
310+
tag query language for more detailed definition.
313311
"""
314312
tagql = self._transform_tags(**tags)
315313

316-
if metric_type is None:
317-
metric_type = 'metrics'
318-
319314
return self._get(self._get_metrics_tags_url(self._get_url(metric_type)) + '/{}'.format(tagql))
320315

321316
def create_metric_definition(self, metric_type, metric_id, **tags):
322317
"""
323318
Create metric definition with custom definition. **tags should be a set of tags, such as
324319
units, env ..
325-
326-
Use methods create_gauge_definition and create_availability_definition to avoid using
327-
MetricType.Gauge / MetricType.Availability
328320
"""
329321
item = { 'id': metric_id }
330322
if len(tags) > 0:
@@ -345,18 +337,6 @@ def create_metric_definition(self, metric_type, metric_id, **tags):
345337
raise e
346338

347339
return True
348-
349-
def create_gauge_definition(self, metric_id, **tags):
350-
"""
351-
See create_metric_definition
352-
"""
353-
return self.create_metric_definition(MetricType.Gauge, metric_id, **tags)
354-
355-
def create_availability_definition(self, metric_id, **tags):
356-
"""
357-
See create_metric_definition
358-
"""
359-
return self.create_metric_definition(MetricType.Availability, metric_id, **tags)
360340

361341
def query_metric_tags(self, metric_type, metric_id):
362342
"""
@@ -373,7 +353,7 @@ def update_metric_tags(self, metric_type, metric_id, **tags):
373353

374354
def delete_metric_tags(self, metric_type, metric_id, **deleted_tags):
375355
"""
376-
Delete one or more tags from the metric definition. The tag values must match what's stored on the server.
356+
Delete one or more tags from the metric definition.
377357
"""
378358
tags = self._transform_tags(**deleted_tags)
379359
tags_url = self._get_metrics_tags_url(self._get_metrics_single_url(metric_type, metric_id)) + '/{0}'.format(tags)

0 commit comments

Comments
 (0)