riemann-client-6.1.3/0000755000175000017500000000000012614652301014010 5ustar samsam00000000000000riemann-client-6.1.3/LICENSE0000664000175000017500000000206712540022654015024 0ustar samsam00000000000000The MIT License (MIT) Copyright (c) 2014 Sam Clements Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. riemann-client-6.1.3/setup.cfg0000644000175000017500000000007312614652301015631 0ustar samsam00000000000000[egg_info] tag_date = 0 tag_build = tag_svn_revision = 0 riemann-client-6.1.3/docs/0000755000175000017500000000000012614652301014740 5ustar samsam00000000000000riemann-client-6.1.3/docs/riemann_client.transport.rst0000664000175000017500000000017712540022654022523 0ustar samsam00000000000000Transport API ============= .. automodule:: riemann_client.transport :members: :undoc-members: :show-inheritance: riemann-client-6.1.3/docs/conf.py0000664000175000017500000000144512540022654016245 0ustar samsam00000000000000# -- General configuration ------------------------------------------------ import os import riemann_client if not os.environ.get('READTHEDOCS', None): import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] master_doc = 'index' exclude_patterns = ['_build'] # General information about the project. project = u'riemann-client' copyright = u'2014, ' + riemann_client.__author__ version = release = riemann_client.__version__ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.viewcode' ] autodoc_member_order = 'bysource' autoclass_content = 'both' riemann-client-6.1.3/docs/index.rst0000664000175000017500000000023712540022654016605 0ustar samsam00000000000000.. include:: ../README.rst .. toctree:: :hidden: Introduction Client API Transport API riemann-client-6.1.3/docs/riemann_client.client.rst0000664000175000017500000000016612540022654021743 0ustar samsam00000000000000Client API ========== .. automodule:: riemann_client.client :members: :undoc-members: :show-inheritance: riemann-client-6.1.3/riemann_client.egg-info/0000755000175000017500000000000012614652301020471 5ustar samsam00000000000000riemann-client-6.1.3/riemann_client.egg-info/dependency_links.txt0000644000175000017500000000000112614652301024537 0ustar samsam00000000000000 riemann-client-6.1.3/riemann_client.egg-info/requires.txt0000644000175000017500000000011312614652301023064 0ustar samsam00000000000000click>=3.1,<4.0 protobuf-py3>=2.5.1,<3.0.0 [docs] sphinx sphinx_rtd_theme riemann-client-6.1.3/riemann_client.egg-info/SOURCES.txt0000644000175000017500000000141312614652301022354 0ustar samsam00000000000000LICENSE MANIFEST.in README.rst setup.py docs/conf.py docs/index.rst docs/riemann_client.client.rst docs/riemann_client.transport.rst riemann_client/__init__.py riemann_client/client.py riemann_client/command.py riemann_client/riemann_pb2.py riemann_client/riemann_pb2_py2.py riemann_client/riemann_pb2_py3.py riemann_client/transport.py riemann_client.egg-info/PKG-INFO riemann_client.egg-info/SOURCES.txt riemann_client.egg-info/dependency_links.txt riemann_client.egg-info/entry_points.txt riemann_client.egg-info/requires.txt riemann_client.egg-info/top_level.txt tests/__init__.py tests/conftest.py tests/test_riemann_auto_flushing_queued_client.py tests/test_riemann_client.py tests/test_riemann_command.py tests/test_riemann_queued_client.py tests/test_riemann_transport.pyriemann-client-6.1.3/riemann_client.egg-info/entry_points.txt0000644000175000017500000000010012614652301023756 0ustar samsam00000000000000[console_scripts] riemann-client = riemann_client.command:main riemann-client-6.1.3/riemann_client.egg-info/PKG-INFO0000644000175000017500000002052512614652301021572 0ustar samsam00000000000000Metadata-Version: 1.1 Name: riemann-client Version: 6.1.3 Summary: A Riemann client and command line tool Home-page: https://github.com/borntyping/python-riemann-client Author: Sam Clements Author-email: sam.clements@datasift.com License: MIT Description: ============== riemann-client ============== .. image:: http://img.shields.io/pypi/v/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/pypi/l/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/travis/borntyping/python-riemann-client/master.svg :target: https://travis-ci.org/borntyping/python-riemann-client | A `Riemann `_ client library and command line tool for Python. It supports UDP and TCP transports, queries, and all metric types. The client library aims to provide a simple, minimal API does not require direct interaction with protocol buffers. There is also a queued client that can queue or batch events and then send them in a single message. * `Source on GitHub `_ * `Documentation on Read the Docs `_ * `Packages on PyPI `_ Usage ----- As a command line tool:: riemann-client [--host HOST] [--port PORT] send [-s SERVICE] [-S STATE] [-m METRIC] [...] riemann-client [--host HOST] [--port PORT] query QUERY The host and port used by the command line tool can also be set with the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables. By default, ``localhost:5555`` will be used. As a library:: import riemann_client.client with riemann_client.client.Client() as client: client.event(service="riemann-client", state="awesome") client.query("service = 'riemann-client'") A more detailed example, using both a non-default transport and a queued client:: from riemann_client.transport import TCPTransport from riemann_client.client import QueuedClient with QueuedClient(TCPTransport("localhost", 5555)) as client: client.event(service="one", metric_f=0.1) client.event(service="two", metric_f=0.2) client.flush() The ``QueuedClient`` class modifies the ``event()`` method to add events to a queue instead of immediately sending them, and adds the ``flush()`` method to send the current event queue as a single message. Installation ------------ ``riemann-client`` requires Python 2.6 or above, and can be installed with ``pip install riemann-client``. It will use Google's `protobuf`_ library when running under Python 2, and `GreatFruitOmsk`_'s `protobuf-py3`_ fork when running under Python 3. Python 3 support is experimental and is likley to use Google's `protobuf` once it supports Python 3 fully. .. _protobuf: https://pypi.python.org/pypi/protobuf .. _GreatFruitOmsk: https://github.com/GreatFruitOmsk .. _protobuf-py3: https://pypi.python.org/pypi/protobuf-py3 Requirements ^^^^^^^^^^^^ * `click `_ * `protobuf`_ (when using Python 2) * `protobuf-py3`_ (when using Python 3) Testing (Linux/OSX) ------- Testing is done with `tox`_:: tox .. _tox: https://tox.readthedocs.org/en/latest/ Changelog --------- Version 6.1.3 ^^^^^^^^^^^^^ * Added ``--echo/--no-echo`` option to the CLI. Version 6.1.2 ^^^^^^^^^^^^^ * Fixed tests inclusion in tarball. Version 6.1.1 ^^^^^^^^^^^^^ * Fixed socket error handling in ``riemann_client.client.AutoFlushingQueuedClient``. Version 6.1.0 ^^^^^^^^^^^^^ * ``riemann_client.client.AutoFlushingQueuedClient`` added. Version 6.0.0 ^^^^^^^^^^^^^ * ``riemann_client.client.Client.create_dict`` only returns event fields that are set on the Protocol Buffers ``Event`` object * ``riemann-client send ...`` only outputs fields that were set on the message Version 5.1.0 ^^^^^^^^^^^^^ * Added Python 3 support * Changed ``riemann_client.riemann_pb2`` to wrap ``_py2`` and ``_py3`` modules * Changed ``setup.py`` to dynamically select a ``protobuf`` dependency Version 5.0.x ^^^^^^^^^^^^^ * Added API documentation (http://riemann-client.readthedocs.org/) * Replaced ``argparse`` with ``click`` for an improved CLI * Various command line parameters changed * ``--event-host`` became ``--host`` * ``--print`` was removed, ``send`` always prints the sent event * Minor fixes to ``QueuedClient`` API * ``UDPTransport.send`` returns ``None`` instead of ``NotImplemented`` Version 4.2.x ^^^^^^^^^^^^^ * Added ``events()`` and ``send_events()`` methods to the client * Added ``clear_queue()`` method to the queued client * Add ``--timeout`` option for TCP based transports Version 4.1.x ^^^^^^^^^^^^^ * Full Riemann protocol support (TLS transport, event attributes) * Fixes for multiple broken features (``--tags``, ``--print``) * Raise errors when clients are used incorrectly * Client displays errors from Riemann nicely * Relaxed version requirements to fit CentOS 6 packages Version 3.0.x ^^^^^^^^^^^^^ * Renamed module from ``riemann`` to ``riemann_client`` * Command line interface was rewritten, and is now the only part of the library that respects the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables * Support for querying the Riemann index was added * Internally, transports now define ``send`` instead of ``write``, and ``TCPTransport.send`` returns Riemann's response message Licence ------- ``riemann-client`` is licensed under the `MIT Licence`_. The protocol buffer definition is sourced from the `Riemann Java client`_, which is licensed under the `Apache Licence`_. .. _MIT Licence: http://opensource.org/licenses/MIT .. _Riemann Java client: https://github.com/aphyr/riemann-java-client/blob/0c4a1a255be6f33069d7bb24d0cc7efb71bf4bc8/src/main/proto/riemann/proto.proto .. _Apache Licence: http://www.apache.org/licenses/LICENSE-2.0 Authors ------- ``riemann-client`` was written by `Sam Clements `_, while working at `DataSift `_. .. image:: https://0.gravatar.com/avatar/8dd5661684a7385fe723b7e7588e91ee?d=https%3A%2F%2Fidenticons.github.com%2Fe83ef7586374403a328e175927b98cac.png&r=x&s=40 .. image:: https://1.gravatar.com/avatar/a3a6d949b43b6b880ffb3e277a65f49d?d=https%3A%2F%2Fidenticons.github.com%2F065affbc170e2511eeacb3bd0e975ec1.png&r=x&s=40 Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking Classifier: Topic :: System :: Systems Administration riemann-client-6.1.3/riemann_client.egg-info/top_level.txt0000644000175000017500000000001712614652301023221 0ustar samsam00000000000000riemann_client riemann-client-6.1.3/tests/0000755000175000017500000000000012614652301015152 5ustar samsam00000000000000riemann-client-6.1.3/tests/test_riemann_queued_client.py0000644000175000017500000000400612565064346023135 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import py.test import riemann_client.client import riemann_client.riemann_pb2 import riemann_client.transport @py.test.fixture def queued_client(request, string_transport): """A Riemann client using the StringIO transport and QueuedClient""" client = riemann_client.client.QueuedClient(transport=string_transport) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def using_simple_queue(queued_client): """An event queue with a single event""" queued_client.event(service='test') @py.test.fixture def large_queue(queued_client): """An event queue with 100 events""" items = ['-->{0}<--'.format(i) for i in range(0, 1000)] for description in items: queued_client.event(service='queue', description=description) return items def test_simple_queue_event(queued_client, using_simple_queue): assert queued_client.queue.events[0].service == 'test' def test_simple_queue_length(queued_client, using_simple_queue): assert len(queued_client.queue.events) == 1 def test_simple_queue_event_not_sent(queued_client, using_simple_queue): assert "test" not in queued_client.transport.string.getvalue() def test_simple_queue_event_sent(queued_client, using_simple_queue): queued_client.flush() assert "test" in queued_client.transport.string.getvalue() def test_deciqueue_length(queued_client, large_queue): assert len(queued_client.queue.events) == len(large_queue) def test_deciqueue_output(queued_client, large_queue): queued_client.flush() for description in large_queue: assert description in queued_client.transport.string.getvalue() def test_deciqueue_flush(queued_client, large_queue): queued_client.flush() assert len(queued_client.queue.events) == 0 def test_clear_queue(queued_client, using_simple_queue): queued_client.clear_queue() assert len(queued_client.queue.events) == 0 riemann-client-6.1.3/tests/test_riemann_command.py0000644000175000017500000000355612614651760021733 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import re import socket import click.testing import riemann_client.command def run_cli(args): args = ['-T', 'none'] + list(args) runner = click.testing.CliRunner() result = runner.invoke(riemann_client.command.main, args) assert result.exit_code == 0 return result def strip(string): return re.sub('\s+', '', string) def assert_output_eq(args, expected): assert strip(run_cli(args).output) == strip(expected) def test_send_empty_message(): assert_output_eq(['send'], '{"host": "%s"}' % socket.gethostname()) POPULATED_MESSAGE = """{ "attributes": { "key": "value" }, "description": "description", "host": "%s", "metric_f": 11.1, "service": "service", "state": "state", "tags": [ "tag" ], "time": 1408030991, "ttl": 120 } """ % socket.gethostname() def test_send(): assert_output_eq([ 'send', '--attribute', 'key=value', '--description', 'description', '--metric_f', '11.1', '--service', 'service', '--state', 'state', '--tag', 'tag', '--time', '1408030991', '--ttl', '120' ], POPULATED_MESSAGE) def test_send_short(): assert_output_eq([ 'send', '-a', 'key=value', '-d', 'description', '-m', '11.1', '-s', 'service', '-S', 'state', '-t', 'tag', '-T', '1408030991', '-l', '120' ], POPULATED_MESSAGE) def test_send_noecho(): assert_output_eq([ 'send', '--attribute', 'key=value', '--description', 'description', '--metric_f', '11.1', '--service', 'service', '--state', 'state', '--tag', 'tag', '--time', '1408030991', '--ttl', '120', '--no-echo' ], '') def test_query(): assert_output_eq(['query', 'true'], '[]') riemann-client-6.1.3/tests/test_riemann_client.py0000644000175000017500000000723512565064346021574 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import socket import sys import uuid import py.test import riemann_client.client import riemann_client.riemann_pb2 import riemann_client.transport if sys.version_info >= (3,): basestring = str @py.test.fixture def client(request, string_transport): client = riemann_client.client.Client(transport=string_transport) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def unique(): return str(uuid.uuid4()) def test_default_transport(): assert riemann_client.client.Client() class TestClient(object): def test_service(self, client): client.event(service='test event') assert 'test event' in client.transport.string.getvalue() def test_default_hostname(self, client, event): event = client.event().events[0] assert socket.gethostname() == event.host assert socket.gethostname() in client.transport.string.getvalue() def test_custom_hostname(self, client): event = client.event(host="test.example.com").events[0] assert "test.example.com" == event.host assert "test.example.com" in client.transport.string.getvalue() def test_tags(self, client, unique): client.event(tags=[unique]) assert unique in client.transport.string.getvalue() def test_attributes(self, client, unique): client.event(attributes={'key': unique}) assert unique in client.transport.string.getvalue() def test_event_cls(self, event): assert isinstance(event, riemann_client.riemann_pb2.Event) def test_query(self, client): assert client.query('true') == [] def test_udp_query(self): transport = riemann_client.transport.UDPTransport() client = riemann_client.client.Client(transport) with py.test.raises(Exception): client.query('true') def test_events(self, client): message = client.events({'service': 'one'}, {'service': 'two'}) assert message.events[0].service == 'one' assert message.events[1].service == 'two' def test_events_len(self, client): message = client.events({'service': 'one'}, {'service': 'two'}) assert len(message.events) == 2 @py.test.fixture def event(unique): return riemann_client.client.Client.create_event({ 'host': 'test.example.com', 'tags': [unique], 'attributes': { unique: unique } }) class TestCreateEvent(object): def test_host(self, event): assert event.host == 'test.example.com' def test_tags(self, event, unique): assert unique in event.tags def test_attributes(self, event, unique): assert event.attributes[0].key == unique assert event.attributes[0].value == unique @py.test.fixture def event_as_dict(event): return riemann_client.client.Client.create_dict(event) class TestCreateDict(object): def test_host(self, event, event_as_dict): assert event.host == event_as_dict['host'] def test_host_type(self, event_as_dict): assert isinstance(event_as_dict['host'], basestring) def test_tags(self, event, event_as_dict): for tag in event.tags: assert tag in event_as_dict['tags'] def test_tags_type(self, event_as_dict): assert isinstance(event_as_dict['tags'], list) def test_attibutes(self, event, event_as_dict): for attr in event.attributes: assert event_as_dict['attributes'][attr.key] == attr.value def test_attibutes_type(self, event_as_dict): assert isinstance(event_as_dict['attributes'], dict) riemann-client-6.1.3/tests/conftest.py0000644000175000017500000000114312565064346017363 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import sys import py.test import riemann_client.transport if sys.version_info >= (3,): from io import StringIO as StringIO else: from StringIO import StringIO class StringTransport(riemann_client.transport.Transport): def connect(self): self.string = StringIO() def send(self, message): self.string.write(str(message.SerializeToString())) message.ok = True return message def disconnect(self): self.string.close() @py.test.fixture def string_transport(): return StringTransport() riemann-client-6.1.3/tests/__init__.py0000644000175000017500000000000012565064346017264 0ustar samsam00000000000000riemann-client-6.1.3/tests/test_riemann_auto_flushing_queued_client.py0000644000175000017500000001672312565064346026075 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import py.test import socket import time import riemann_client.client import riemann_client.riemann_pb2 import riemann_client.transport @py.test.fixture def blank_transport(): return riemann_client.transport.BlankTransport() class BrokenTransport(riemann_client.transport.Transport): def connect(self): pass def disconnect(self): pass def send(self, *args, **kwargs): raise socket.error(32, '[Errno 32] Broken pipe') @py.test.fixture def broken_transport(): return BrokenTransport() @py.test.fixture def auto_flushing_queued_client(request, blank_transport): """A Riemann client using the StringIO transport and AutoFlushingQueuedClient with max_delay=300 and max_batch_size=5000""" client = riemann_client.client.AutoFlushingQueuedClient( transport=blank_transport, max_delay=300, max_batch_size=5000, stay_connected=True) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def auto_flushing_queued_client_delay(request, blank_transport): """A Riemann client using the StringIO transport and AutoFlushingQueuedClient with max_delay=1 and max_batch_size=5000""" client = riemann_client.client.AutoFlushingQueuedClient( transport=blank_transport, max_delay=0.05, max_batch_size=5000, stay_connected=True) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def auto_flushing_queued_client_batch5(request, blank_transport): """A Riemann client using the StringIO transport and AutoFlushingQueuedClient with max_delay=300 and max_batch_size=5""" client = riemann_client.client.AutoFlushingQueuedClient( transport=blank_transport, max_delay=300, max_batch_size=5, stay_connected=True) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def auto_flushing_queued_client_batch5_broken_f(request, broken_transport): """A Riemann client using the StringIO transport and AutoFlushingQueuedClient with max_delay=300 and max_batch_size=5""" client = riemann_client.client.AutoFlushingQueuedClient( transport=broken_transport, max_delay=300, max_batch_size=5, stay_connected=True, clear_on_fail=False) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def auto_flushing_queued_client_batch5_broken_t(request, broken_transport): """A Riemann client using the StringIO transport and AutoFlushingQueuedClient with max_delay=300 and max_batch_size=5""" client = riemann_client.client.AutoFlushingQueuedClient( transport=broken_transport, max_delay=300, max_batch_size=5, stay_connected=True, clear_on_fail=True) client.transport.connect() @request.addfinalizer def disconnect(): client.transport.disconnect() return client @py.test.fixture def using_simple_queue(auto_flushing_queued_client): """An event queue with a single event""" auto_flushing_queued_client.event(service='test') @py.test.fixture def large_queue(auto_flushing_queued_client): """An event queue with 100 events""" items = ['-->{0}<--'.format(i) for i in range(0, 1000)] for description in items: auto_flushing_queued_client.event(service='queue', description=description) return items def test_simple_queue_event(auto_flushing_queued_client, using_simple_queue): assert auto_flushing_queued_client.queue.events[0].service == 'test' def test_simple_queue_length(auto_flushing_queued_client, using_simple_queue): assert len(auto_flushing_queued_client.queue.events) == 1 def test_simple_queue_event_not_sent(auto_flushing_queued_client, using_simple_queue): assert len(auto_flushing_queued_client.transport.events) == 0 def test_simple_queue_event_sent(auto_flushing_queued_client, using_simple_queue): auto_flushing_queued_client.flush() assert len(auto_flushing_queued_client.transport.events) == 1 def test_deciqueue_length(auto_flushing_queued_client, large_queue): assert len(auto_flushing_queued_client.queue.events) == len(large_queue) def test_deciqueue_output(auto_flushing_queued_client, large_queue): auto_flushing_queued_client.flush() # note that these will be ordered, and all events will be in a single # protobuf flush, so we can find them in messages[0] for idx, description in enumerate(large_queue): assert (description == auto_flushing_queued_client. transport.events[idx].description) def test_deciqueue_flush(auto_flushing_queued_client, large_queue): auto_flushing_queued_client.flush() assert len(auto_flushing_queued_client.queue.events) == 0 def test_clear_queue(auto_flushing_queued_client, using_simple_queue): auto_flushing_queued_client.clear_queue() assert len(auto_flushing_queued_client.queue.events) == 0 def test_batchsize_autoflush(auto_flushing_queued_client_batch5): auto_flushing_queued_client_batch5.clear_queue() sent = 0 to_send = 100 for i in range(to_send): auto_flushing_queued_client_batch5.event( service='test', description='{0:03d}'.format(i)) sent += 1 assert len(auto_flushing_queued_client_batch5.queue.events) == 0 assert len(auto_flushing_queued_client_batch5.transport) == sent assert ('000' == auto_flushing_queued_client_batch5. transport.events[0].description) assert ('{0:03d}'.format(to_send - 1) == auto_flushing_queued_client_batch5.transport. events[-1].description) def test_timer_autoflush(auto_flushing_queued_client_delay): auto_flushing_queued_client_delay.clear_queue() auto_flushing_queued_client_delay.event(service='test', description='timer_test') assert len(auto_flushing_queued_client_delay.transport) == 0 assert len(auto_flushing_queued_client_delay.queue.events) == 1 time.sleep(0.1) assert len(auto_flushing_queued_client_delay.transport) == 1 assert len(auto_flushing_queued_client_delay.queue.events) == 0 assert ('timer_test' == auto_flushing_queued_client_delay. transport.events[0].description) def test_clear_on_fail_false(auto_flushing_queued_client_batch5_broken_f): auto_flushing_queued_client_batch5_broken_f.clear_queue() sent = 0 to_send = 10 for i in range(to_send): auto_flushing_queued_client_batch5_broken_f.event( service='test', description='{0:03d}'.format(i)) sent += 1 assert (len(auto_flushing_queued_client_batch5_broken_f.queue.events) == sent) def test_clear_on_fail_true(auto_flushing_queued_client_batch5_broken_t): auto_flushing_queued_client_batch5_broken_t.clear_queue() sent = 0 to_send = 10 for i in range(to_send): auto_flushing_queued_client_batch5_broken_t.event( service='test', description='{0:03d}'.format(i)) sent += 1 assert (len(auto_flushing_queued_client_batch5_broken_t.queue.events) == 0) riemann-client-6.1.3/tests/test_riemann_transport.py0000644000175000017500000000207112565064346022343 0ustar samsam00000000000000from __future__ import absolute_import, unicode_literals import py.test import riemann_client.riemann_pb2 import riemann_client.transport from riemann_client.transport import socket_recvall class FakeSocket(object): def __init__(self): self.data = [b'hello', b'world', b''] def recv(self, bufsize): return self.data.pop(0) def test_socket_recvall(): assert socket_recvall(FakeSocket(), 10) == b'helloworld' def test_socket_recvall_short(): assert socket_recvall(FakeSocket(), 5) == b'hello' @py.test.fixture def tcp_transport(): return riemann_client.transport.TCPTransport() def test_not_yet_connected(tcp_transport): with py.test.raises(RuntimeError): tcp_transport.send(riemann_client.riemann_pb2.Msg()) def test_address_property(tcp_transport): assert tcp_transport.address == (tcp_transport.host, tcp_transport.port) def test_transport_enter(string_transport): assert not hasattr(string_transport, 'string') with string_transport: assert hasattr(string_transport, 'string') riemann-client-6.1.3/README.rst0000644000175000017500000001375712614651760015524 0ustar samsam00000000000000============== riemann-client ============== .. image:: http://img.shields.io/pypi/v/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/pypi/l/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/travis/borntyping/python-riemann-client/master.svg :target: https://travis-ci.org/borntyping/python-riemann-client | A `Riemann `_ client library and command line tool for Python. It supports UDP and TCP transports, queries, and all metric types. The client library aims to provide a simple, minimal API does not require direct interaction with protocol buffers. There is also a queued client that can queue or batch events and then send them in a single message. * `Source on GitHub `_ * `Documentation on Read the Docs `_ * `Packages on PyPI `_ Usage ----- As a command line tool:: riemann-client [--host HOST] [--port PORT] send [-s SERVICE] [-S STATE] [-m METRIC] [...] riemann-client [--host HOST] [--port PORT] query QUERY The host and port used by the command line tool can also be set with the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables. By default, ``localhost:5555`` will be used. As a library:: import riemann_client.client with riemann_client.client.Client() as client: client.event(service="riemann-client", state="awesome") client.query("service = 'riemann-client'") A more detailed example, using both a non-default transport and a queued client:: from riemann_client.transport import TCPTransport from riemann_client.client import QueuedClient with QueuedClient(TCPTransport("localhost", 5555)) as client: client.event(service="one", metric_f=0.1) client.event(service="two", metric_f=0.2) client.flush() The ``QueuedClient`` class modifies the ``event()`` method to add events to a queue instead of immediately sending them, and adds the ``flush()`` method to send the current event queue as a single message. Installation ------------ ``riemann-client`` requires Python 2.6 or above, and can be installed with ``pip install riemann-client``. It will use Google's `protobuf`_ library when running under Python 2, and `GreatFruitOmsk`_'s `protobuf-py3`_ fork when running under Python 3. Python 3 support is experimental and is likley to use Google's `protobuf` once it supports Python 3 fully. .. _protobuf: https://pypi.python.org/pypi/protobuf .. _GreatFruitOmsk: https://github.com/GreatFruitOmsk .. _protobuf-py3: https://pypi.python.org/pypi/protobuf-py3 Requirements ^^^^^^^^^^^^ * `click `_ * `protobuf`_ (when using Python 2) * `protobuf-py3`_ (when using Python 3) Testing (Linux/OSX) ------- Testing is done with `tox`_:: tox .. _tox: https://tox.readthedocs.org/en/latest/ Changelog --------- Version 6.1.3 ^^^^^^^^^^^^^ * Added ``--echo/--no-echo`` option to the CLI. Version 6.1.2 ^^^^^^^^^^^^^ * Fixed tests inclusion in tarball. Version 6.1.1 ^^^^^^^^^^^^^ * Fixed socket error handling in ``riemann_client.client.AutoFlushingQueuedClient``. Version 6.1.0 ^^^^^^^^^^^^^ * ``riemann_client.client.AutoFlushingQueuedClient`` added. Version 6.0.0 ^^^^^^^^^^^^^ * ``riemann_client.client.Client.create_dict`` only returns event fields that are set on the Protocol Buffers ``Event`` object * ``riemann-client send ...`` only outputs fields that were set on the message Version 5.1.0 ^^^^^^^^^^^^^ * Added Python 3 support * Changed ``riemann_client.riemann_pb2`` to wrap ``_py2`` and ``_py3`` modules * Changed ``setup.py`` to dynamically select a ``protobuf`` dependency Version 5.0.x ^^^^^^^^^^^^^ * Added API documentation (http://riemann-client.readthedocs.org/) * Replaced ``argparse`` with ``click`` for an improved CLI * Various command line parameters changed * ``--event-host`` became ``--host`` * ``--print`` was removed, ``send`` always prints the sent event * Minor fixes to ``QueuedClient`` API * ``UDPTransport.send`` returns ``None`` instead of ``NotImplemented`` Version 4.2.x ^^^^^^^^^^^^^ * Added ``events()`` and ``send_events()`` methods to the client * Added ``clear_queue()`` method to the queued client * Add ``--timeout`` option for TCP based transports Version 4.1.x ^^^^^^^^^^^^^ * Full Riemann protocol support (TLS transport, event attributes) * Fixes for multiple broken features (``--tags``, ``--print``) * Raise errors when clients are used incorrectly * Client displays errors from Riemann nicely * Relaxed version requirements to fit CentOS 6 packages Version 3.0.x ^^^^^^^^^^^^^ * Renamed module from ``riemann`` to ``riemann_client`` * Command line interface was rewritten, and is now the only part of the library that respects the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables * Support for querying the Riemann index was added * Internally, transports now define ``send`` instead of ``write``, and ``TCPTransport.send`` returns Riemann's response message Licence ------- ``riemann-client`` is licensed under the `MIT Licence`_. The protocol buffer definition is sourced from the `Riemann Java client`_, which is licensed under the `Apache Licence`_. .. _MIT Licence: http://opensource.org/licenses/MIT .. _Riemann Java client: https://github.com/aphyr/riemann-java-client/blob/0c4a1a255be6f33069d7bb24d0cc7efb71bf4bc8/src/main/proto/riemann/proto.proto .. _Apache Licence: http://www.apache.org/licenses/LICENSE-2.0 Authors ------- ``riemann-client`` was written by `Sam Clements `_, while working at `DataSift `_. .. image:: https://0.gravatar.com/avatar/8dd5661684a7385fe723b7e7588e91ee?d=https%3A%2F%2Fidenticons.github.com%2Fe83ef7586374403a328e175927b98cac.png&r=x&s=40 .. image:: https://1.gravatar.com/avatar/a3a6d949b43b6b880ffb3e277a65f49d?d=https%3A%2F%2Fidenticons.github.com%2F065affbc170e2511eeacb3bd0e975ec1.png&r=x&s=40 riemann-client-6.1.3/setup.py0000755000175000017500000000302212614651760015532 0ustar samsam00000000000000#!/usr/bin/env python2.6 import sys import setuptools if sys.version_info >= (3,): protobuf = 'protobuf-py3>=2.5.1,<3.0.0' else: protobuf = 'protobuf>=2.3.0,<3.0.0' setuptools.setup( name='riemann-client', version='6.1.3', author="Sam Clements", author_email="sam.clements@datasift.com", url="https://github.com/borntyping/python-riemann-client", description="A Riemann client and command line tool", long_description=open('README.rst').read(), license="MIT", packages=[ 'riemann_client', ], install_requires=[ 'click>=3.1,<4.0', protobuf ], extras_require={ 'docs': [ 'sphinx', 'sphinx_rtd_theme' ] }, entry_points={ 'console_scripts': [ 'riemann-client = riemann_client.command:main', ] }, classifiers=[ 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Software Development :: Libraries', 'Topic :: System :: Monitoring', 'Topic :: System :: Networking', 'Topic :: System :: Systems Administration' ], ) riemann-client-6.1.3/MANIFEST.in0000644000175000017500000000011712565557446015570 0ustar samsam00000000000000include LICENSE recursive-include docs conf.py *.rst recursive-include tests * riemann-client-6.1.3/riemann_client/0000755000175000017500000000000012614652301016777 5ustar samsam00000000000000riemann-client-6.1.3/riemann_client/riemann_pb2_py2.py0000664000175000017500000003116112540022654022343 0ustar samsam00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! from google.protobuf import descriptor from google.protobuf import message from google.protobuf import reflection from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) DESCRIPTOR = descriptor.FileDescriptor( name='riemann.proto', package='', serialized_pb='\n\rriemann.proto\"\x81\x01\n\x05State\x12\x0c\n\x04time\x18\x01 \x01(\x03\x12\r\n\x05state\x18\x02 \x01(\t\x12\x0f\n\x07service\x18\x03 \x01(\t\x12\x0c\n\x04host\x18\x04 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\x0c\n\x04once\x18\x06 \x01(\x08\x12\x0c\n\x04tags\x18\x07 \x03(\t\x12\x0b\n\x03ttl\x18\x08 \x01(\x02\"\xce\x01\n\x05\x45vent\x12\x0c\n\x04time\x18\x01 \x01(\x03\x12\r\n\x05state\x18\x02 \x01(\t\x12\x0f\n\x07service\x18\x03 \x01(\t\x12\x0c\n\x04host\x18\x04 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\x0c\n\x04tags\x18\x07 \x03(\t\x12\x0b\n\x03ttl\x18\x08 \x01(\x02\x12\x1e\n\nattributes\x18\t \x03(\x0b\x32\n.Attribute\x12\x15\n\rmetric_sint64\x18\r \x01(\x12\x12\x10\n\x08metric_d\x18\x0e \x01(\x01\x12\x10\n\x08metric_f\x18\x0f \x01(\x02\"\x17\n\x05Query\x12\x0e\n\x06string\x18\x01 \x01(\t\"g\n\x03Msg\x12\n\n\x02ok\x18\x02 \x01(\x08\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x16\n\x06states\x18\x04 \x03(\x0b\x32\x06.State\x12\x15\n\x05query\x18\x05 \x01(\x0b\x32\x06.Query\x12\x16\n\x06\x65vents\x18\x06 \x03(\x0b\x32\x06.Event\"\'\n\tAttribute\x12\x0b\n\x03key\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x01(\tB\x1a\n\x11\x63om.aphyr.riemannB\x05Proto') _STATE = descriptor.Descriptor( name='State', full_name='State', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ descriptor.FieldDescriptor( name='time', full_name='State.time', index=0, number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='state', full_name='State.state', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='service', full_name='State.service', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='host', full_name='State.host', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='description', full_name='State.description', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='once', full_name='State.once', index=5, number=6, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='tags', full_name='State.tags', index=6, number=7, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='ttl', full_name='State.ttl', index=7, number=8, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=18, serialized_end=147, ) _EVENT = descriptor.Descriptor( name='Event', full_name='Event', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ descriptor.FieldDescriptor( name='time', full_name='Event.time', index=0, number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='state', full_name='Event.state', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='service', full_name='Event.service', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='host', full_name='Event.host', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='description', full_name='Event.description', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='tags', full_name='Event.tags', index=5, number=7, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='ttl', full_name='Event.ttl', index=6, number=8, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='attributes', full_name='Event.attributes', index=7, number=9, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='metric_sint64', full_name='Event.metric_sint64', index=8, number=13, type=18, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='metric_d', full_name='Event.metric_d', index=9, number=14, type=1, cpp_type=5, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='metric_f', full_name='Event.metric_f', index=10, number=15, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=150, serialized_end=356, ) _QUERY = descriptor.Descriptor( name='Query', full_name='Query', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ descriptor.FieldDescriptor( name='string', full_name='Query.string', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=358, serialized_end=381, ) _MSG = descriptor.Descriptor( name='Msg', full_name='Msg', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ descriptor.FieldDescriptor( name='ok', full_name='Msg.ok', index=0, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='error', full_name='Msg.error', index=1, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='states', full_name='Msg.states', index=2, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='query', full_name='Msg.query', index=3, number=5, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='events', full_name='Msg.events', index=4, number=6, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=383, serialized_end=486, ) _ATTRIBUTE = descriptor.Descriptor( name='Attribute', full_name='Attribute', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ descriptor.FieldDescriptor( name='key', full_name='Attribute.key', index=0, number=1, type=9, cpp_type=9, label=2, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), descriptor.FieldDescriptor( name='value', full_name='Attribute.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode("", "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=488, serialized_end=527, ) _EVENT.fields_by_name['attributes'].message_type = _ATTRIBUTE _MSG.fields_by_name['states'].message_type = _STATE _MSG.fields_by_name['query'].message_type = _QUERY _MSG.fields_by_name['events'].message_type = _EVENT class State(message.Message): __metaclass__ = reflection.GeneratedProtocolMessageType DESCRIPTOR = _STATE # @@protoc_insertion_point(class_scope:State) class Event(message.Message): __metaclass__ = reflection.GeneratedProtocolMessageType DESCRIPTOR = _EVENT # @@protoc_insertion_point(class_scope:Event) class Query(message.Message): __metaclass__ = reflection.GeneratedProtocolMessageType DESCRIPTOR = _QUERY # @@protoc_insertion_point(class_scope:Query) class Msg(message.Message): __metaclass__ = reflection.GeneratedProtocolMessageType DESCRIPTOR = _MSG # @@protoc_insertion_point(class_scope:Msg) class Attribute(message.Message): __metaclass__ = reflection.GeneratedProtocolMessageType DESCRIPTOR = _ATTRIBUTE # @@protoc_insertion_point(class_scope:Attribute) # @@protoc_insertion_point(module_scope) riemann-client-6.1.3/riemann_client/command.py0000644000175000017500000001150112614651760020775 0ustar samsam00000000000000"""Riemann command line client""" from __future__ import absolute_import, print_function import json import sys import click import riemann_client import riemann_client.client import riemann_client.transport __all__ = ['main'] class CommandLineClient(riemann_client.client.Client): """Prints to STDERR when an error message is recived from Riemann""" def __exit__(self, exc_type, exc_value, traceback): super(CommandLineClient, self).__exit__(exc_type, exc_value, traceback) if isinstance(exc_type, riemann_client.transport.RiemannError): click.echo("The server responded with an error: {0}".format( exc_value.message), file=sys.stderr) exit(1) class Pair(click.ParamType): """A key value parameter seperated with an '=' symbol""" name = 'pair' def convert(self, value, param, ctx): key, value = value.split('=', 1) return key.strip(), value.strip() def echo_event(data): """Echo a json dump of an object using click""" return click.echo(json.dumps(data, sort_keys=True, indent=2)) @click.group() @click.version_option(version=riemann_client.__version__) @click.option('--host', '-H', type=click.STRING, default='localhost', envvar='RIEMANN_HOST', help='Riemann server hostname.') @click.option('--port', '-P', type=click.INT, default=5555, envvar='RIEMANN_PORT', help='Riemann server port.') @click.option('--transport', '-T', 'transport_type', default='tcp', type=click.Choice(['udp', 'tcp', 'tls', 'none']), help='The protocol to use to connect to Riemann.') @click.option('--timeout', '-I', type=click.FLOAT, default=None, help='Timeout for TCP based connections.') @click.option('--ca-certs', '-C', type=click.Path(), help='A CA certificate bundle for TLS connections.') @click.pass_context def main(ctx, host, port, transport_type, timeout, ca_certs): """Connects to a Riemann server to send events or query the index By default, will attempt to contact Riemann on localhost:5555 over TCP. The RIEMANN_HOST and RIEMANN_PORT environment variables can be used to configure the host and port used. Command line parameters will override the environment variables. Use `-T none` to test commands without actually connecting to a server. """ if transport_type == 'udp': if timeout is not None: ctx.fail('--timeout cannot be used with the UDP transport') transport = riemann_client.transport.UDPTransport(host, port) elif transport_type == 'tcp': transport = riemann_client.transport.TCPTransport(host, port, timeout) elif transport_type == 'tls': if ca_certs is None: ctx.fail('--ca-certs must be set when using the TLS transport') transport = riemann_client.transport.TLSTransport( host, port, timeout, ca_certs) elif transport_type == 'none': transport = riemann_client.transport.BlankTransport() ctx.obj = transport @main.command() @click.option('-T', '--time', type=click.INT, help="Event timestamp (unix format)") @click.option('-S', '--state', type=click.STRING, help="Event state") @click.option('-s', '--service', type=click.STRING, help="Event service name") @click.option('-h', '--host', type=click.STRING, help="Event hostname (uses system's by default)") @click.option('-d', '--description', type=click.STRING, help="Event description") @click.option('-t', '--tag', type=click.STRING, multiple=True, help="Event tag (multiple)") @click.option('-l', '--ttl', type=click.INT, help="Event time to live in seconds") @click.option('-a', '--attr', '--attribute', type=Pair(), multiple=True, help="Event attribute (key=value, multiple)") @click.option('-m', '--metric', '--metric_f', type=click.FLOAT, help="Event metric (uses metric_f)") @click.option('--echo/--no-echo', default=True, help="Echo event object after sending") @click.pass_obj def send(transport, time, state, host, description, service, tag, attribute, ttl, metric_f, echo): """Send a single event to Riemann""" client = CommandLineClient(transport) event = client.create_event({ 'time': time, 'state': state, 'host': host, 'description': description, 'service': service, 'tags': tag, 'attributes': dict(attribute), 'ttl': ttl, 'metric_f': metric_f }) with client: client.send_event(event) if echo: echo_event(client.create_dict(event)) @main.command() @click.argument('query', 'query') @click.pass_obj def query(transport, query): """Query the Riemann server""" with CommandLineClient(transport) as client: echo_event(client.query(query)) riemann-client-6.1.3/riemann_client/transport.py0000644000175000017500000001305212565064346021421 0ustar samsam00000000000000"""Transports are used for direct communication with the Riemann server. They are usually used inside a :py:class:`.Client`, and are used to send and receive protocol buffer objects.""" from __future__ import absolute_import import abc import socket import ssl import struct import riemann_client.riemann_pb2 # Default arguments HOST = 'localhost' PORT = 5555 TIMEOUT = None def socket_recvall(socket, length, bufsize=4096): """A helper method to read of bytes from a socket to a maximum length""" data = b"" while len(data) < length: data += socket.recv(bufsize) return data class RiemannError(Exception): """Raised when the Riemann server returns an error message""" pass class Transport(object): """Abstract transport definition Subclasses must implement the :py:meth:`.connect`, :py:meth:`.disconnect` and :py:meth:`.send` methods. Can be used as a context manager, which will call :py:meth:`.connect` on entry and :py:meth:`.disconnect` on exit. """ __metaclass__ = abc.ABCMeta def __enter__(self): self.connect() return self def __exit__(self, exc_type, exc_value, traceback): self.disconnect() @abc.abstractmethod def connect(self): pass @abc.abstractmethod def disconnect(self): pass @abc.abstractmethod def send(self): pass class SocketTransport(Transport): """Provides common methods for Transports that use a sockets""" def __init__(self, host=HOST, port=PORT): self.host = host self.port = port @property def address(self): """ :returns: A tuple describing the address to connect to :rtype: (host, port) """ return self.host, self.port @property def socket(self): """Returns the socket after checking it has been created""" if not hasattr(self, '_socket'): raise RuntimeError("Transport has not been connected!") return self._socket @socket.setter def socket(self, value): self._socket = value class UDPTransport(SocketTransport): def connect(self): """Creates a UDP socket""" self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) def disconnect(self): """Closes the socket""" self.socket.close() def send(self, message): """Sends a message, but does not return a response :returns: None - can't receive a response over UDP """ self.socket.sendto(message.SerializeToString(), self.address) return None class TCPTransport(SocketTransport): def __init__(self, host=HOST, port=PORT, timeout=TIMEOUT): """Communicates with Riemann over TCP :param str host: The hostname to connect to :param int port: The port to connect to :param int timeout: The time in seconds to wait before raising an error """ super(TCPTransport, self).__init__(host, port) self.timeout = timeout def connect(self): """Connects to the given host""" self.socket = socket.create_connection(self.address, self.timeout) def disconnect(self): """Closes the socket""" self.socket.close() def send(self, message): """Sends a message to a Riemann server and returns it's response :param message: The message to send to the Riemann server :returns: The response message from Riemann :raises RiemannError: if the server returns an error """ message = message.SerializeToString() self.socket.sendall(struct.pack('!I', len(message)) + message) length = struct.unpack('!I', self.socket.recv(4))[0] response = riemann_client.riemann_pb2.Msg() response.ParseFromString(socket_recvall(self.socket, length)) if not response.ok: raise RiemannError(response.error) return response class TLSTransport(TCPTransport): def __init__(self, host=HOST, port=PORT, timeout=TIMEOUT, ca_certs=None): """Communicates with Riemann over TCP + TLS Options are the same as :py:class:`.TCPTransport` unless noted :param str ca_certs: Path to a CA Cert bundle used to create the socket """ super(TLSTransport, self).__init__(host, port, timeout) self.ca_certs = ca_certs def connect(self): """Connects using :py:meth:`TLSTransport.connect` and wraps with TLS""" super(TLSTransport, self).connect() self.socket = ssl.wrap_socket( self.socket, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_certs) class BlankTransport(Transport): """A transport that collects events in a list, and has no connection Used by ``--transport none``, which is useful for testing commands without contacting a Riemann server. This is also used by the automated tests in ``riemann_client/tests/test_riemann_command.py``. """ def __init__(self, *args, **kwargs): self.events = [] def connect(self): """Creates a list to hold messages""" pass def send(self, message): """Adds a message to the list, returning a fake 'ok' response :returns: A response message with ``ok = True`` """ for event in message.events: self.events.append(event) reply = riemann_client.riemann_pb2.Msg() reply.ok = True return reply def disconnect(self): """Clears the list of messages""" pass def __len__(self): return len(self.events) riemann-client-6.1.3/riemann_client/riemann_pb2.py0000664000175000017500000000047212540022654021552 0ustar samsam00000000000000"""Wraps the riemann_pb2_py2 and riemann_pb2_py3 modules""" import sys __all__ = ['Event', 'Msg', 'Query', 'Attribute'] if sys.version_info >= (3,): from riemann_client.riemann_pb2_py3 import (Event, Msg, Query, Attribute) else: from riemann_client.riemann_pb2_py2 import (Event, Msg, Query, Attribute) riemann-client-6.1.3/riemann_client/client.py0000644000175000017500000003117212565064346020646 0ustar samsam00000000000000"""Clients manage the main user facing API, and provide functions for sending events and querying the Riemann server. UDP, TCP and TLS transports are provided by the :py:mod:`riemann_client.transport` module, and the protocol buffer objects are provided by the :py:mod:`riemann_client.riemann_pb2` module. """ from __future__ import absolute_import import logging try: from logging import NullHandler except ImportError: # Create a NullHandler class in logging for python 2.6 class NullHandler(logging.Handler): def emit(self, record): pass import socket try: from threading import RLock from threading import Timer except ImportError: RLock = None Timer = None import time import riemann_client.riemann_pb2 import riemann_client.transport logger = logging.getLogger(__name__) logger.addHandler(NullHandler()) class Client(object): """A client for sending events and querying a Riemann server. Two sets of methods are provided - an API dealing directly with protocol buffer objects and an extended API that takes and returns dictionaries representing events. Protocol buffer API: - :py:meth:`.send_event` - :py:meth:`.send_events` - :py:meth:`.send_query` Extended API: - :py:meth:`.event` - :py:meth:`.events` - :py:meth:`.query` Clients do not directly manage connections to a Riemann server - these are managed by :py:class:`riemann_client.transport.Transport` instances, which provide methods to read and write messages to the server. Client instances can be used as a context manager, and will connect and disconnect the transport when entering and exiting the context. >>> with Client(transport) as client: ... # Calls transport.connect() ... client.query('true') ... # Calls transport.disconnect() """ def __init__(self, transport=None): if transport is None: transport = riemann_client.transport.TCPTransport() self.transport = transport def __enter__(self): self.transport.connect() return self def __exit__(self, exc_type, exc_value, traceback): self.transport.disconnect() @staticmethod def create_event(data): """Translates a dictionary of event attributes to an Event object :param dict data: The attributes to be set on the event :returns: A protocol buffer ``Event`` object """ event = riemann_client.riemann_pb2.Event() event.host = socket.gethostname() event.tags.extend(data.pop('tags', [])) for key, value in data.pop('attributes', {}).items(): attribute = event.attributes.add() attribute.key, attribute.value = key, value for name, value in data.items(): if value is not None: setattr(event, name, value) return event def send_events(self, events): """Sends multiple events to Riemann in a single message :param events: A list or iterable of ``Event`` objects :returns: The response message from Riemann """ message = riemann_client.riemann_pb2.Msg() for event in events: message.events.add().MergeFrom(event) return self.transport.send(message) def send_event(self, event): """Sends a single event to Riemann :param event: An ``Event`` protocol buffer object :returns: The response message from Riemann """ return self.send_events((event,)) def events(self, *events): """Sends multiple events in a single message >>> client.events({'service': 'riemann-client', 'state': 'awesome'}) :param \*events: event dictionaries for :py:func:`create_event` :returns: The response message from Riemann """ return self.send_events(self.create_event(e) for e in events) def event(self, **data): """Sends an event, using keyword arguments to create an Event >>> client.event(service='riemann-client', state='awesome') :param \*\*data: keyword arguments used for :py:func:`create_event` :returns: The response message from Riemann """ return self.send_event(self.create_event(data)) @staticmethod def create_dict(event): """Translates an Event object to a dictionary of event attributes All attributes are included, so ``create_dict(create_event(input))`` may return more attributes than were present in the input. :param event: A protocol buffer ``Event`` object :returns: A dictionary of event attributes """ data = dict() for descriptor, value in event.ListFields(): if descriptor.name == 'tags': value = list(value) elif descriptor.name == 'attributes': value = dict(((a.key, a.value) for a in value)) data[descriptor.name] = value return data def send_query(self, query): """Sends a query to the Riemann server :returns: The response message from Riemann """ message = riemann_client.riemann_pb2.Msg() message.query.string = query return self.transport.send(message) def query(self, query): """Sends a query to the Riemann server >>> client.query('true') :returns: A list of event dictionaries taken from the response :raises Exception: if used with a :py:class:`.UDPTransport` """ if isinstance(self.transport, riemann_client.transport.UDPTransport): raise Exception('Cannot query the Riemann server over UDP') response = self.send_query(query) return [self.create_dict(e) for e in response.events] class QueuedClient(Client): """A Riemann client using a queue that can be used to batch send events. A message object is used as a queue, with the :py:meth:`.send_event` and :py:meth:`.send_events` methods adding new events to the message and the :py:meth:`.flush` sending the message. """ def __init__(self, transport=None): super(QueuedClient, self).__init__(transport) self.clear_queue() def flush(self): """Sends the waiting message to Riemann :returns: The response message from Riemann """ response = self.transport.send(self.queue) self.clear_queue() return response def send_event(self, event): """Adds a single event to the queued message :returns: None - nothing has been sent to the Riemann server yet """ self.send_events((event,)) return None def send_events(self, events): """Adds multiple events to the queued message :returns: None - nothing has been sent to the Riemann server yet """ for event in events: self.queue.events.add().MergeFrom(event) return None def clear_queue(self): """Resets the message/queue to a blank :py:class:`.Msg` object""" self.queue = riemann_client.riemann_pb2.Msg() if RLock and Timer: # noqa class AutoFlushingQueuedClient(QueuedClient): """A Riemann client using a queue and a timer that will automatically flush its contents if either: - the queue size exceeds :param max_batch_size: or - more than :param max_delay: has elapsed since the last flush and the queue is non-empty. if :param stay_connected: is False, then the transport will be disconnected after each flush and reconnected at the beginning of the next flush. if :param clear_on_fail: is True, then the client will discard its buffer after the second retry in the event of a socket error. A message object is used as a queue, and the following methods are given: - :py:meth:`.send_event` - add a new event to the queue - :py:meth:`.send_events` add a tuple of new events to the queue - :py:meth:`.event` - add a new event to the queue from keyword arguments - :py:meth:`.events` - add new events to the queue from dictionaries - :py:meth:`.flush` - manually force flush the queue to the transport """ def __init__(self, transport, max_delay=0.5, max_batch_size=100, stay_connected=False, clear_on_fail=False): super(AutoFlushingQueuedClient, self).__init__(transport) self.stay_connected = stay_connected self.clear_on_fail = clear_on_fail self.max_delay = max_delay self.max_batch_size = max_batch_size self.lock = RLock() self.event_counter = 0 self.last_flush = time.time() self.timer = None # start the timer self.start_timer() def connect(self): """Connect the transport if it is not already connected.""" if not self.is_connected(): self.transport.connect() def is_connected(self): """Check whether the transport is connected.""" try: # this will throw an exception whenever socket isn't connected self.transport.socket.type return True except (AttributeError, RuntimeError, socket.error): return False def event(self, **data): """Enqueues an event, using keyword arguments to create an Event >>> client.event(service='riemann-client', state='awesome') :param \*\*data: keyword arguments used for :py:func:`create_event` """ self.send_events((self.create_event(data),)) def events(self, *events): """Enqueues multiple events in a single message >>> client.events({'service': 'riemann-client', >>> 'state': 'awesome'}) :param \*events: event dictionaries for :py:func:`create_event` :returns: The response message from Riemann """ self.send_events(self.create_event(evd) for evd in events) def send_events(self, events): """Enqueues multiple events :param events: A list or iterable of ``Event`` objects :returns: The response message from Riemann """ with self.lock: for event in events: self.queue.events.add().MergeFrom(event) self.event_counter += 1 self.check_for_flush() def flush(self): """Sends the events in the queue to Riemann in a single protobuf message :returns: The response message from Riemann """ response = None with self.lock: if not self.is_connected(): self.connect() try: response = super(AutoFlushingQueuedClient, self).flush() except socket.error: # log and retry logger.warn("Socket error on flushing. " "Attempting reconnect and retry...") try: self.transport.disconnect() self.connect() response = ( super(AutoFlushingQueuedClient, self).flush()) except: logger.warn("Socket error on flushing " "second attempt. Batch discarded.") self.transport.disconnect() if self.clear_on_fail: self.clear_queue() self.event_counter = 0 if not self.stay_connected: self.transport.disconnect() self.last_flush = time.time() self.start_timer() return response def check_for_flush(self): """Checks the conditions for flushing the queue""" if (self.event_counter >= self.max_batch_size or (time.time() - self.last_flush) >= self.max_delay): self.flush() def start_timer(self): """Cycle the timer responsible for periodically flushing the queue """ if self.timer: self.timer.cancel() self.timer = Timer(self.max_delay, self.check_for_flush) self.timer.daemon = True self.timer.start() def stop_timer(self): """Stops the current timer a :py:meth:`.flush` event will reactviate the timer """ self.timer.cancel() riemann-client-6.1.3/riemann_client/__init__.py0000644000175000017500000000020312614651760021113 0ustar samsam00000000000000"""A Python Riemann client and command line tool""" __version__ = '6.1.3' __author__ = 'Sam Clements ' riemann-client-6.1.3/riemann_client/riemann_pb2_py3.py0000664000175000017500000003323612540022654022351 0ustar samsam00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: riemann.proto from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection import sys if sys.version_info >= (3,): #some constants that are python2 only unicode = str long = int range = range unichr = chr def b(s): return s.encode("latin-1") def u(s): return s else: #some constants that are python2 only range = xrange unicode = unicode long = long unichr = unichr def b(s): return s # Workaround for standalone backslash def u(s): return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) DESCRIPTOR = _descriptor.FileDescriptor( name='riemann.proto', package='', serialized_pb=b('\n\rriemann.proto\"\x81\x01\n\x05State\x12\x0c\n\x04time\x18\x01 \x01(\x03\x12\r\n\x05state\x18\x02 \x01(\t\x12\x0f\n\x07service\x18\x03 \x01(\t\x12\x0c\n\x04host\x18\x04 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\x0c\n\x04once\x18\x06 \x01(\x08\x12\x0c\n\x04tags\x18\x07 \x03(\t\x12\x0b\n\x03ttl\x18\x08 \x01(\x02\"\xce\x01\n\x05\x45vent\x12\x0c\n\x04time\x18\x01 \x01(\x03\x12\r\n\x05state\x18\x02 \x01(\t\x12\x0f\n\x07service\x18\x03 \x01(\t\x12\x0c\n\x04host\x18\x04 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\x0c\n\x04tags\x18\x07 \x03(\t\x12\x0b\n\x03ttl\x18\x08 \x01(\x02\x12\x1e\n\nattributes\x18\t \x03(\x0b\x32\n.Attribute\x12\x15\n\rmetric_sint64\x18\r \x01(\x12\x12\x10\n\x08metric_d\x18\x0e \x01(\x01\x12\x10\n\x08metric_f\x18\x0f \x01(\x02\"\x17\n\x05Query\x12\x0e\n\x06string\x18\x01 \x01(\t\"g\n\x03Msg\x12\n\n\x02ok\x18\x02 \x01(\x08\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x16\n\x06states\x18\x04 \x03(\x0b\x32\x06.State\x12\x15\n\x05query\x18\x05 \x01(\x0b\x32\x06.Query\x12\x16\n\x06\x65vents\x18\x06 \x03(\x0b\x32\x06.Event\"\'\n\tAttribute\x12\x0b\n\x03key\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x01(\tB\x1a\n\x11\x63om.aphyr.riemannB\x05Proto')) _STATE = _descriptor.Descriptor( name='State', full_name='State', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='time', full_name='State.time', index=0, number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='state', full_name='State.state', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='service', full_name='State.service', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='host', full_name='State.host', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='description', full_name='State.description', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='once', full_name='State.once', index=5, number=6, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='tags', full_name='State.tags', index=6, number=7, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='ttl', full_name='State.ttl', index=7, number=8, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=18, serialized_end=147, ) _EVENT = _descriptor.Descriptor( name='Event', full_name='Event', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='time', full_name='Event.time', index=0, number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='state', full_name='Event.state', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='service', full_name='Event.service', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='host', full_name='Event.host', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='description', full_name='Event.description', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='tags', full_name='Event.tags', index=5, number=7, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='ttl', full_name='Event.ttl', index=6, number=8, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='attributes', full_name='Event.attributes', index=7, number=9, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='metric_sint64', full_name='Event.metric_sint64', index=8, number=13, type=18, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='metric_d', full_name='Event.metric_d', index=9, number=14, type=1, cpp_type=5, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='metric_f', full_name='Event.metric_f', index=10, number=15, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=150, serialized_end=356, ) _QUERY = _descriptor.Descriptor( name='Query', full_name='Query', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='string', full_name='Query.string', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=358, serialized_end=381, ) _MSG = _descriptor.Descriptor( name='Msg', full_name='Msg', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='ok', full_name='Msg.ok', index=0, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='error', full_name='Msg.error', index=1, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='states', full_name='Msg.states', index=2, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='query', full_name='Msg.query', index=3, number=5, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='events', full_name='Msg.events', index=4, number=6, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=383, serialized_end=486, ) _ATTRIBUTE = _descriptor.Descriptor( name='Attribute', full_name='Attribute', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='key', full_name='Attribute.key', index=0, number=1, type=9, cpp_type=9, label=2, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='value', full_name='Attribute.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=unicode(b(""), "utf-8"), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], serialized_start=488, serialized_end=527, ) _EVENT.fields_by_name['attributes'].message_type = _ATTRIBUTE _MSG.fields_by_name['states'].message_type = _STATE _MSG.fields_by_name['query'].message_type = _QUERY _MSG.fields_by_name['events'].message_type = _EVENT DESCRIPTOR.message_types_by_name['State'] = _STATE DESCRIPTOR.message_types_by_name['Event'] = _EVENT DESCRIPTOR.message_types_by_name['Query'] = _QUERY DESCRIPTOR.message_types_by_name['Msg'] = _MSG DESCRIPTOR.message_types_by_name['Attribute'] = _ATTRIBUTE State = _reflection.GeneratedProtocolMessageType('State', (_message.Message,), { 'DESCRIPTOR': _STATE, # @@protoc_insertion_point(class_scope:State) }) Event = _reflection.GeneratedProtocolMessageType('Event', (_message.Message,), { 'DESCRIPTOR': _EVENT, # @@protoc_insertion_point(class_scope:Event) }) Query = _reflection.GeneratedProtocolMessageType('Query', (_message.Message,), { 'DESCRIPTOR': _QUERY, # @@protoc_insertion_point(class_scope:Query) }) Msg = _reflection.GeneratedProtocolMessageType('Msg', (_message.Message,), { 'DESCRIPTOR': _MSG, # @@protoc_insertion_point(class_scope:Msg) }) Attribute = _reflection.GeneratedProtocolMessageType('Attribute', (_message.Message,), { 'DESCRIPTOR': _ATTRIBUTE, # @@protoc_insertion_point(class_scope:Attribute) }) DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), b('\n\021com.aphyr.riemannB\005Proto')) # @@protoc_insertion_point(module_scope) riemann-client-6.1.3/PKG-INFO0000644000175000017500000002052512614652301015111 0ustar samsam00000000000000Metadata-Version: 1.1 Name: riemann-client Version: 6.1.3 Summary: A Riemann client and command line tool Home-page: https://github.com/borntyping/python-riemann-client Author: Sam Clements Author-email: sam.clements@datasift.com License: MIT Description: ============== riemann-client ============== .. image:: http://img.shields.io/pypi/v/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/pypi/l/riemann-client.svg :target: https://pypi.python.org/pypi/riemann-client .. image:: http://img.shields.io/travis/borntyping/python-riemann-client/master.svg :target: https://travis-ci.org/borntyping/python-riemann-client | A `Riemann `_ client library and command line tool for Python. It supports UDP and TCP transports, queries, and all metric types. The client library aims to provide a simple, minimal API does not require direct interaction with protocol buffers. There is also a queued client that can queue or batch events and then send them in a single message. * `Source on GitHub `_ * `Documentation on Read the Docs `_ * `Packages on PyPI `_ Usage ----- As a command line tool:: riemann-client [--host HOST] [--port PORT] send [-s SERVICE] [-S STATE] [-m METRIC] [...] riemann-client [--host HOST] [--port PORT] query QUERY The host and port used by the command line tool can also be set with the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables. By default, ``localhost:5555`` will be used. As a library:: import riemann_client.client with riemann_client.client.Client() as client: client.event(service="riemann-client", state="awesome") client.query("service = 'riemann-client'") A more detailed example, using both a non-default transport and a queued client:: from riemann_client.transport import TCPTransport from riemann_client.client import QueuedClient with QueuedClient(TCPTransport("localhost", 5555)) as client: client.event(service="one", metric_f=0.1) client.event(service="two", metric_f=0.2) client.flush() The ``QueuedClient`` class modifies the ``event()`` method to add events to a queue instead of immediately sending them, and adds the ``flush()`` method to send the current event queue as a single message. Installation ------------ ``riemann-client`` requires Python 2.6 or above, and can be installed with ``pip install riemann-client``. It will use Google's `protobuf`_ library when running under Python 2, and `GreatFruitOmsk`_'s `protobuf-py3`_ fork when running under Python 3. Python 3 support is experimental and is likley to use Google's `protobuf` once it supports Python 3 fully. .. _protobuf: https://pypi.python.org/pypi/protobuf .. _GreatFruitOmsk: https://github.com/GreatFruitOmsk .. _protobuf-py3: https://pypi.python.org/pypi/protobuf-py3 Requirements ^^^^^^^^^^^^ * `click `_ * `protobuf`_ (when using Python 2) * `protobuf-py3`_ (when using Python 3) Testing (Linux/OSX) ------- Testing is done with `tox`_:: tox .. _tox: https://tox.readthedocs.org/en/latest/ Changelog --------- Version 6.1.3 ^^^^^^^^^^^^^ * Added ``--echo/--no-echo`` option to the CLI. Version 6.1.2 ^^^^^^^^^^^^^ * Fixed tests inclusion in tarball. Version 6.1.1 ^^^^^^^^^^^^^ * Fixed socket error handling in ``riemann_client.client.AutoFlushingQueuedClient``. Version 6.1.0 ^^^^^^^^^^^^^ * ``riemann_client.client.AutoFlushingQueuedClient`` added. Version 6.0.0 ^^^^^^^^^^^^^ * ``riemann_client.client.Client.create_dict`` only returns event fields that are set on the Protocol Buffers ``Event`` object * ``riemann-client send ...`` only outputs fields that were set on the message Version 5.1.0 ^^^^^^^^^^^^^ * Added Python 3 support * Changed ``riemann_client.riemann_pb2`` to wrap ``_py2`` and ``_py3`` modules * Changed ``setup.py`` to dynamically select a ``protobuf`` dependency Version 5.0.x ^^^^^^^^^^^^^ * Added API documentation (http://riemann-client.readthedocs.org/) * Replaced ``argparse`` with ``click`` for an improved CLI * Various command line parameters changed * ``--event-host`` became ``--host`` * ``--print`` was removed, ``send`` always prints the sent event * Minor fixes to ``QueuedClient`` API * ``UDPTransport.send`` returns ``None`` instead of ``NotImplemented`` Version 4.2.x ^^^^^^^^^^^^^ * Added ``events()`` and ``send_events()`` methods to the client * Added ``clear_queue()`` method to the queued client * Add ``--timeout`` option for TCP based transports Version 4.1.x ^^^^^^^^^^^^^ * Full Riemann protocol support (TLS transport, event attributes) * Fixes for multiple broken features (``--tags``, ``--print``) * Raise errors when clients are used incorrectly * Client displays errors from Riemann nicely * Relaxed version requirements to fit CentOS 6 packages Version 3.0.x ^^^^^^^^^^^^^ * Renamed module from ``riemann`` to ``riemann_client`` * Command line interface was rewritten, and is now the only part of the library that respects the ``RIEMANN_HOST`` and ``RIEMANN_PORT`` environment variables * Support for querying the Riemann index was added * Internally, transports now define ``send`` instead of ``write``, and ``TCPTransport.send`` returns Riemann's response message Licence ------- ``riemann-client`` is licensed under the `MIT Licence`_. The protocol buffer definition is sourced from the `Riemann Java client`_, which is licensed under the `Apache Licence`_. .. _MIT Licence: http://opensource.org/licenses/MIT .. _Riemann Java client: https://github.com/aphyr/riemann-java-client/blob/0c4a1a255be6f33069d7bb24d0cc7efb71bf4bc8/src/main/proto/riemann/proto.proto .. _Apache Licence: http://www.apache.org/licenses/LICENSE-2.0 Authors ------- ``riemann-client`` was written by `Sam Clements `_, while working at `DataSift `_. .. image:: https://0.gravatar.com/avatar/8dd5661684a7385fe723b7e7588e91ee?d=https%3A%2F%2Fidenticons.github.com%2Fe83ef7586374403a328e175927b98cac.png&r=x&s=40 .. image:: https://1.gravatar.com/avatar/a3a6d949b43b6b880ffb3e277a65f49d?d=https%3A%2F%2Fidenticons.github.com%2F065affbc170e2511eeacb3bd0e975ec1.png&r=x&s=40 Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking Classifier: Topic :: System :: Systems Administration