Skip to content

Commit

Permalink
Merge pull request #12 from sandipb/master
Browse files Browse the repository at this point in the history
Some visibility and perf improvements
  • Loading branch information
etdub committed Aug 21, 2018
2 parents 3a1e9ba + 3971aa5 commit e82c6b7
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 169 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ MANIFEST
*.egg-info
.coverage
.tox
.vscode
114 changes: 68 additions & 46 deletions bin/speakeasy
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
#!/usr/bin/env python

from __future__ import absolute_import
from __future__ import print_function

import argparse
import logging
from speakeasy.speakeasy import Speakeasy
import socket
import time
import threading
import signal
import itertools
import pdb

from speakeasy.speakeasy import Speakeasy

logger = logging.getLogger()
quit_event = threading.Event()


def init_logger(verbose):
if verbose:
Expand All @@ -18,48 +27,61 @@ def init_logger(verbose):
handler.setFormatter(formatter)
logger.addHandler(handler)


def catch_quit_signal(signum, stack):
logger.warn("Caught signal %d", signum)
quit_event.set()


def main():
parser = argparse.ArgumentParser(description='Run Speakeasy server')
parser.add_argument('-H', '--host', required=False, default=socket.getfqdn(),
help='Hostname to emit metrics as')
parser.add_argument('-ms', '--metric-socket', required=True,
help='Metric socket to listen on')
parser.add_argument('-cp', '--cmd-port', required=True,
help='Port to receive commands on')
parser.add_argument('-pp', '--pub-port', required=False,
help='Port to publish updates on')
parser.add_argument('-e', '--emitter', required=True,
help='Module to emit data through periodically')
parser.add_argument('-ea', '--emitter-args', required=False, nargs='*',
help='Arguments to be passed to emitter module')
parser.add_argument('-ei', '--emission-interval', default=60, required=False, type=float,
help='Frequency to emit data (seconds)')
parser.add_argument('-l', '--legacy', required=False, type=str,
help='Optional legacy socket to listen for incoming metrics')
parser.add_argument('-sm', '--socket-mod', required=False, default=None, type=str,
help='File mode for metric socket')
parser.add_argument('-v', '--verbose', required=False, default=False, action='store_true',
help='Enable verbose logging')

args = parser.parse_args()

init_logger(args.verbose)

logger.info('Start speakeasy')
socket_mod = int(args.socket_mod, base=8) if args.socket_mod else None
server = Speakeasy(args.host, args.metric_socket, args.cmd_port,
args.pub_port, args.emitter, args.emitter_args,
args.emission_interval, args.legacy,
socket_mod=socket_mod)
server.start()

while True:
try:
time.sleep(1)
except (KeyboardInterrupt, Exception), e:
logger.warn("Exception... exiting - {0}".format(e))
server.shutdown()
break

if __name__=='__main__':
main()
parser = argparse.ArgumentParser(description='Run Speakeasy server')
parser.add_argument('-H', '--host', required=False, default=socket.getfqdn(),
help='Hostname to emit metrics as')
parser.add_argument('-ms', '--metric-socket', required=True,
help='Metric socket to listen on')
parser.add_argument('-cp', '--cmd-port', required=True,
help='Port to receive commands on')
parser.add_argument('-pp', '--pub-port', required=False,
help='Port to publish updates on')
parser.add_argument('-e', '--emitter', required=True,
help='Module to emit data through periodically')
parser.add_argument('-ea', '--emitter-args', required=False, nargs='*', action="append", default=[],
help='Arguments to be passed to emitter module')
parser.add_argument('-ei', '--emission-interval', default=60, required=False, type=float,
help='Frequency to emit data (seconds)')
parser.add_argument('-l', '--legacy', required=False, type=str,
help='Optional legacy socket to listen for incoming metrics')
parser.add_argument('-sm', '--socket-mod', required=False, default=None, type=str,
help='File mode for metric socket')
parser.add_argument('-v', '--verbose', required=False, default=False, action='store_true',
help='Enable verbose logging')

args = parser.parse_args()

init_logger(args.verbose)

logger.info('Start speakeasy')

socket_mod = int(args.socket_mod, base=8) if args.socket_mod else None
server = Speakeasy(args.host, args.metric_socket, args.cmd_port,
args.pub_port, args.emitter, itertools.chain(*args.emitter_args),
args.emission_interval, args.legacy,
socket_mod=socket_mod)
server.start()

signal.signal(signal.SIGTERM, catch_quit_signal)
signal.signal(signal.SIGINT, catch_quit_signal)
signal.signal(signal.SIGPIPE, catch_quit_signal)
signal.signal(signal.SIGUSR1, lambda x, y: pdb.set_trace())

while not quit_event.is_set():
try:
quit_event.wait(10)
except Exception as e:
logger.info("Exception (%s)... exiting", e)

server.shutdown()


if __name__ == '__main__':
main()
5 changes: 3 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import sphinx_rtd_theme

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + "/.."))

# -- General configuration ------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Content:

intro
quickstart

speakeasy

Indices and tables
==================
Expand Down
17 changes: 17 additions & 0 deletions docs/speakeasy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Module documentation
====================

.. automodule:: speakeasy.speakeasy
:members:
:undoc-members:

.. automethod:: __init__

Included emitters
=================

Simple
------

.. automodule:: speakeasy.emitter.simple

3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
max-line-length=120

42 changes: 35 additions & 7 deletions speakeasy/emitter/simple.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
"""The simple emitter writes metrics every interval to a file.
To use this emitter provide the emitter arg `filename` to write to. If an arg is not provided,
this emitter will attempt to write to `metrics.out` barring any permissions issue.
.. code-block:: bash
speakeasy ... --emitter simple --emitter-args filename=/var/tmp/metrics.out
The special names `stdout` or `stderr` will send outputs to the appropriate stream
"""
import logging
import os
import sys

logger = logging.getLogger(__name__)

DEFAULT_FILENAME = "metrics.out"
DEFAULT_SEPARATOR = "|"


class Emitter(object):

def __init__(self, **kwargs):
self.filename = kwargs['filename']
self.filename = kwargs.get('filename', DEFAULT_FILENAME)
self.separator = kwargs.get('separator', DEFAULT_SEPARATOR)

def emit(self, metrics):
fh = None
if self.filename == "stderr":
fh = sys.stderr
elif self.filename == "stdout":
fh = sys.stdout

if fh:
self._emit(fh, metrics)
else:
with open(self.filename, 'a') as fh:
self._emit(fh, metrics)

def _emit(self, fh, metrics):
""" Ship the metrics off """
with open(self.filename, 'a') as fh:
for metric in metrics:
mline = '|'.join([str(m) for m in metric])
logger.debug('Writing metric out to file - {0}'.format(mline))
fh.write(mline+'\n')
for metric in metrics:
mline = self.separator.join([str(m) for m in metric])
fh.write(mline + '\n')
Loading

0 comments on commit e82c6b7

Please sign in to comment.