#!/usr/bin/env python # (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ A Python Statsd implementation with dimensions added """ # set up logging before importing any other components import monasca_agent.common.util as util util.initialize_logging('statsd') import monasca_agent.common.config as cfg import monasca_agent.statsd.reporter as reporter import monasca_agent.statsd.udp as udp # stdlib import argparse import logging import signal import sys # project import monasca_agent.common.aggregator as agg log = logging.getLogger('statsd') class MonascaStatsd(object): """This class is the monasca_statsd daemon. """ def __init__(self, config_path): config = cfg.Config() statsd_config = config.get_config(['Main', 'Statsd']) # Create the aggregator (which is the point of communication between the # server and reporting threads. aggregator = agg.MetricsAggregator( util.get_hostname(), recent_point_threshold=statsd_config['recent_point_threshold'], tenant_id=statsd_config.get( 'global_delegated_tenant', None)) # Start the reporting thread. interval = int(statsd_config['monasca_statsd_interval']) assert 0 < interval self.reporter = reporter.Reporter(interval, aggregator, statsd_config['forwarder_url'], statsd_config.get('event_chunk_size')) # Start the server on an IPv4 stack if statsd_config['non_local_traffic']: server_host = '' else: server_host = 'localhost' self.server = udp.Server( aggregator, server_host, statsd_config['monasca_statsd_port'], forward_to_host=statsd_config.get('monasca_statsd_forward_host'), forward_to_port=int( statsd_config.get('monasca_statsd_forward_port'))) def _handle_sigterm(self, signum, frame): log.debug("Caught sigterm. Stopping run loop.") self.server.stop() def run(self): # Gracefully exit on sigterm. signal.signal(signal.SIGTERM, self._handle_sigterm) # Handle Keyboard Interrupt signal.signal(signal.SIGINT, self._handle_sigterm) # Start the reporting thread before accepting data self.reporter.start() try: try: self.server.start() except Exception as e: log.exception('Error starting server') raise e finally: # The server will block until it's done. Once we're here, shutdown # the reporting thread. self.reporter.stop() self.reporter.join() log.info("monasca_statsd is stopped") def main(): """The main entry point for the unix version of monasca_statsd. """ parser = argparse.ArgumentParser( description='Monasca statsd - statsd server supporting metric dimensions') parser.add_argument( '--config', '--config-file', '-c', help="Location for an alternate config rather than using the default config location.") args = parser.parse_args() monasca_statsd = MonascaStatsd(args.config) monasca_statsd.run() if __name__ == '__main__': sys.exit(main())