diff --git a/README.md b/README.md index 19ec841..5e6793f 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,127 @@ klugman ======= Python library and cmdline tools for accessing Quincy. + + +Examples: + +``` +$ klugman +Usage: + klugman.py [options] [...] + klugman.py (-h | --help) + klugman.py --version + + +$ klugman -h +Klugman - cmdline and client library for StackTach.v3 + +Usage: + klugman.py [options] [...] + klugman.py (-h | --help) + klugman.py --version + +Options: + -h --help Show this help message + --version Show klugman version + --debug Debug mode + -a, --api_version + Which API version to use [default: latest] + --url StackTach.v3 server url [default: http://localhost:8000] + +For a list of possible StackTach commands, use: + klugman help + + +$ klugman help +Klugman - StackTach.v3 client + +Usage: + klugman.py [options] streams [...] + klugman.py num-streams [...] [options] + klugman.py [options] archives [...] + +Options: + -h, --help show command options + + +$ klugman num-streams ++----------+-------+ +| Property | Value | ++----------+-------+ +| count | 19 | ++----------+-------+ + +$ klugman num-streams --state completed ++----------+-------+ +| Property | Value | ++----------+-------+ +| count | 4 | ++----------+-------+ + +$ klugman num-streams --state active ++----------+-------+ +| Property | Value | ++----------+-------+ +| count | 15 | ++----------+-------+ + +$ klugman streams -h +usage: + klugman.py streams [options] + + options: + --id + get stream with id + --details + return events with each stream + --state + return streams in state + --older_than + list streams where first_event < + --younger_than + list streams where last_event > + --trigger_name + list streams with given trigger definition + --distinguishing_traits + list stream with specific distriquishing traits + + Stream states: + collecting - collecting events + ready - ready for processing + triggered - being processed + processed - processing completed + error - pipeline processing failed + commit_error - pipeline result commit failed + + Distinguishing trait format: + "trait:value;trait:value;..." + + +$ klugman streams ++-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Property | Value | ++-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | 17 | +| state | completed | +| name | test_trigger | +| first_event | 2015-01-31 13:21:50.679800 | +| last_event | 2015-01-31 13:36:46.981800 | +| fire_timestamp | 2015-01-30 18:52:03.196602 | +| expire_timestamp | 2015-01-31 14:36:46.981800 | +| distinguishing_traits | {u'instance_id': u'bd8b66f6-745b-45ce-b9c2-43010f8d9cdf', u'timestamp': TimeRange from datetime.datetime(2015, 1, 31, 0, 0) to datetime.datetime(2015, 2, 1, 0, 0)} | +| events | None | ++-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +$ klugman streams --distinguishing_traits instance_id:1438620b-e426-4911-81cd-e5f82219a390 +... + + +$ klugman streams --older_than 01-31-2015T13:30 +... + +$ klugman streams --older_than 01-31-2015T13:30 --state completed +... + +``` + diff --git a/klugman/jsonutil.py b/klugman/jsonutil.py index 94fcc82..ca9f0d8 100644 --- a/klugman/jsonutil.py +++ b/klugman/jsonutil.py @@ -3,17 +3,29 @@ import timex import iso8601 +def _present(dct, name): + return name in dct and dct[name] is not None and dct[name] != 'None' + + def decode_datetime(dct, name): + if not _present(dct, 'datetime'): + return 'n/a' return iso8601.parse_date(dct['datetime'], default_timezone=None) def decode_timerange(dct, name): - begin = iso8601.parse_date(dct['begin'], default_timezone=None) - end = iso8601.parse_date(dct['end'], default_timezone=None) + begin = 'n/a' + if _present(dct, 'begin'): + begin = iso8601.parse_date(dct['begin'], default_timezone=None) + end = 'n/a' + if _present(dct, 'end'): + end = iso8601.parse_date(dct['end'], default_timezone=None) return timex.TimeRange(begin=begin, end=end) def decode_timestamp(dct, name): + if not _present(dct, 'timestamp'): + return 'n/a' timestamp = iso8601.parse_date(dct['timestamp'], default_timezone=None) return timex.Timestamp(timestamp) @@ -24,6 +36,8 @@ DECODE_MAP = {'datetime': decode_datetime, def object_hook(dct): + if dct is None: + return 'n/a' if '__type__' in dct: name = dct['__type__'] decoder = DECODE_MAP[name] diff --git a/klugman/v1.py b/klugman/v1.py index 5fb1661..dc84f96 100644 --- a/klugman/v1.py +++ b/klugman/v1.py @@ -17,10 +17,21 @@ import base import json import jsonutil +import sys from docopt import docopt +def check_state(state): + if state and state not in ["active", "firing", "expiring", "error", + "expire_error", "completed", + "retry_fire", "retry_expire"]: + print "Invalid state. %s not one of 'active, firing, " \ + "expiring, error, expire_error, completed, " \ + "retry_fire or retry_expire" % state + sys.exit(1) + + class Streams(object): """usage: klugman.py streams [options] @@ -33,9 +44,9 @@ class Streams(object): --state return streams in state --older_than - list streams older than datetime + list streams where first_event < --younger_than - list streams younger than datetime + list streams where last_event > --trigger_name list streams with given trigger definition --distinguishing_traits @@ -82,6 +93,7 @@ class Streams(object): traits = arguments.get('--distinguishing_traits') details = arguments.get('--details') + check_state(state) cmd = "streams" if sid: cmd = "streams/%s" % sid @@ -106,20 +118,22 @@ class NumStreams(object): return streams in state --older_than list streams older than datetime + --older_than + list streams where first_event < --younger_than - list streams younger than datetime - --trigger_name - list streams with given trigger definition + list streams where last_event > --distinguishing_traits list stream with specific distriquishing traits Stream states: - collecting - collecting events - ready - ready for processing - triggered - being processed - processed - processing completed - error - pipeline processing failed - commit_error - pipeline result commit failed + active = collecting events + firing = about to process events + expiring = about to expire stream + error = pipeline processing failed + expire_error = pipeline expiry failed + completed = stream processing completed + retry_fire = re-attempt pipeline firing + retry_expire = re-attempt pipeline expiry Distinguishing trait format: "trait:value;trait:value;..." @@ -144,6 +158,8 @@ class NumStreams(object): trigger = arguments.get('--trigger_name') traits = arguments.get('--distinguishing_traits') + check_state(state) + cmd = "streams/count" params = base.remove_empty({'state': state, 'older_than': older,