| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- # Licensed to Cloudera, Inc. under one
- # or more contributor license agreements. See the NOTICE file
- # distributed with this work for additional information
- # regarding copyright ownership. Cloudera, Inc. licenses this file
- # to you 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.
- # Copyright (c) 2015 Cloudera, Inc. All rights reserved.
- import logging
- import time
- from cmf.monitor import schema
- from cmf.monitor.abstract_monitor import CollectionError
- from cmf.monitor.constants import WEB_METRICS_COLLECTION_GOOD, \
- DEFAULT_MONITOR_LOG_RATE, WEB_METRICS_COLLECTION_COMMUNICATION_FAILURE
- from cmf.monitor.generic import AbstractMetricCollector
- from cmf.monitor.generic.adapter import Adapter
- from cmf.monitor.generic.service_defined_metrics import ServiceDefinedMetrics
- from cmf.monitor.generic.utils import SplittingSourceProcessor, visit_json, \
- SimpleMetricsExtractor
- from cmf.throttling_logger import ThrottlingLogger
- from url_util import head_request_with_timeout
- logging.basicConfig()
- LOG = logging.getLogger('HueServerAdapter')
- THROTTLED_LOG = ThrottlingLogger(LOG, DEFAULT_MONITOR_LOG_RATE)
- class _HueIsAliveCollector(AbstractMetricCollector):
- """
- A collector that generates web-metric collection metrics from the hue is alive
- end-point.
- """
- def __init__(self, adapter):
- AbstractMetricCollector.__init__(self, adapter)
- if not isinstance(adapter, HueServerAdapter):
- raise Exception("Unsupported adapter type")
- def update_with_conf(self, conf):
- LOG.info("hue_adapters: _HueIsAliveCollector: update_with_conf: metrics_uri: %s" % self._adapter._get_is_alive_url(conf))
- self._metrics_uri = self._adapter._get_is_alive_url(conf)
- def collect_and_parse(self, conf):
- start = time.time()
- try:
- LOG.info("hue_adapters: _HueIsAliveCollector: _call_is_alive: metrics_uri: %s" % self._metrics_uri)
- self._call_is_alive(self._metrics_uri)
- result = WEB_METRICS_COLLECTION_GOOD
- except Exception, ex:
- THROTTLED_LOG.exception("Error calling is alive at '%s'" %
- (self._metrics_uri,))
- result = CollectionError(WEB_METRICS_COLLECTION_COMMUNICATION_FAILURE)
- now = time.time()
- self._metrics_tuple = result, now, int((now - start) * 1000)
- def _add_metrics(self, service_version, update, collected_metrics, duration):
- update.add_metric(schema.WEB_METRICS_COLLECTION_DURATION, duration)
- if isinstance(collected_metrics, CollectionError):
- update.add_metric(schema.WEB_METRICS_COLLECTION_STATUS,
- collected_metrics.code)
- else:
- update.add_metric(schema.WEB_METRICS_COLLECTION_STATUS,
- collected_metrics)
- return True
- def is_ready_to_report(self, conf, pid):
- if pid is None:
- raise Exception("Pid cannot be None")
- metrics_url = self._adapter._get_is_alive_url(conf)
- if metrics_url is None:
- return AbstractMetricCollector._COLLECTOR_NOT_SUPPORTED
- try:
- self._call_is_alive(metrics_url, 0.5)
- return True
- except Exception, ex:
- pass
- return False
- def _call_is_alive(self, is_alive_url, timeout=None):
- """
- We need this function to make testing eaiser.
- """
- head_request_with_timeout(is_alive_url, timeout=timeout)
- class HueServerAdapter(Adapter):
- """
- An adapter that collects and generates metrics for the HUE_SERVER. The adapter
- collects metrics from a sample file generated by hue. It also generates
- web-metric-collection metrics using an is-alive endpoint exposed by hue.
- Note that the web-metric-collection metrics generation is done as part of the
- sample file metric collection. The reason is that the hue is-alive end-point
- accepts HTTP HEAD requests and we can't use the regular web metric collector
- to generate these metics.
- """
- _HUE_SERVER_METRICS_SAMPLE_FILE_KEY = "location"
- _HUE_SERVER_HTTP_HOST_KEY = "http_host"
- _HUE_SERVER_HTTP_PORT_KEY = "http_port"
- _HUE_SERVER_SSL_ENABLED_KEY = "ssl_enable"
- _SERVICE_RELEASE = 'service_release'
- def __init__(self, safety_valve):
- Adapter.__init__(self, "HUE", "HUE_SERVER", safety_valve)
- self._metrics = None
- self._is_alive_collector = _HueIsAliveCollector(self)
- def read_service_defined_metrics(self, path):
- if path is None:
- raise Exception("A path is required!")
- self._metrics = ServiceDefinedMetrics(path, SplittingSourceProcessor('::'))
- def get_metrics_file(self, conf):
- if conf is None:
- raise Exception("A configuration is required!")
- try:
- return conf.get(
- self.section,
- HueServerAdapter._HUE_SERVER_METRICS_SAMPLE_FILE_KEY)
- except:
- LOG.exception("Failed to retrieve %s from monitoring configuration file" %
- HueServerAdapter._HUE_SERVER_METRICS_SAMPLE_FILE_KEY)
- def _get_is_alive_url(self, conf):
- if conf is None:
- raise Exception("A configuration is required!")
- if not self._is_alive_supported(conf):
- return None
- try:
- host = conf.get(self.section, HueServerAdapter._HUE_SERVER_HTTP_HOST_KEY)
- if host is None:
- LOG.error("%s entry missing from monitoring configuration file" %
- (HueServerAdapter._HUE_SERVER_HTTP_HOST_KEY, ))
- return None
- port = conf.getint(self.section,
- HueServerAdapter._HUE_SERVER_HTTP_PORT_KEY)
- if port is None:
- LOG.error("%s entry missing from monitoring configuration file" %
- (HueServerAdapter._HUE_SERVER_HTTP_PORT_KEY, ))
- return None
- if conf.getboolean_with_default(
- self.section,
- HueServerAdapter._HUE_SERVER_SSL_ENABLED_KEY,
- False):
- url_format = "https://%s:%s/desktop/debug/is_alive"
- else:
- url_format = "http://%s:%s/desktop/debug/is_alive"
- return url_format % (host, port)
- except:
- LOG.exception("Failed to read monitoring configuration file")
- return None
- def parse_metrics_from_file(self, conf, json):
- if json is None:
- raise Exception("a json sample is required")
- if self._metrics is None:
- raise Exception("No metrics have been loaded!")
- role_extractor = SimpleMetricsExtractor(
- self._metrics.get_sources(self._role_type))
- visit_json(json, [role_extractor])
- return role_extractor.metrics
- def add_sample_file_metrics(self, version, update, metrics, accessors):
- for metric_id, value in metrics.iteritems():
- update.add_metric(metric_id, value)
- def get_metrics_sample(self, version):
- return _HUE_SERVER_METRICS_SAMPLE
- def _is_alive_supported(self, conf):
- return True
- def get_adapter_specific_collectors(self):
- return [self._is_alive_collector]
- _HUE_SERVER_METRICS_SAMPLE="""
- {
- "desktop.auth.oauth.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 1234567,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "desktop.auth.saml2.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 0,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "python.threads.count": {
- "value": 42.5
- },
- "desktop.users.logged-in.count": {
- "count": 1
- },
- "python.gc.referrers.count": {
- "value": 0
- },
- "desktop.requests.exceptions.count": {
- "count": 7
- },
- "python.multiprocessing.active": {
- "value": 0
- },
- "desktop.users.count": {
- "value": 2
- },
- "python.gc.referents.count": {
- "value": 0
- },
- "python.threads.active": {
- "value": 52
- },
- "python.threads.daemon": {
- "value": 1
- },
- "desktop.auth.pam.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 0,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "desktop.auth.spnego.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 0,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "desktop.auth.ldap.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 0,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "desktop.requests.aggregate-response-time": {
- "1m_rate": 2.5683487079247715e-101,
- "999_percentile": 11.331326007843018,
- "15m_rate": 4.33344429167876e-8,
- "99_percentile": 11.331326007843018,
- "mean_rate": 0.0005057717284166405,
- "max": 11.331326007843018,
- "sum": 15.07522988319397,
- "min": 0.007016897201538086,
- "5m_rate": 2.0635466335636803e-21,
- "count": 7,
- "75_percentile": 2.34737491607666,
- "std_dev": 4.1352759732033935,
- "95_percentile": 11.331326007843018,
- "avg": 2.15360426902771
- },
- "python.gc.objects.count": {
- "value": 218408
- },
- "python.multiprocessing.count": {
- "value": 0
- },
- "desktop.auth.openid.authentication-time": {
- "1m_rate": 0,
- "999_percentile": 0,
- "15m_rate": 0,
- "99_percentile": 0,
- "mean_rate": 0,
- "max": 0,
- "sum": 0,
- "min": 0,
- "5m_rate": 0,
- "count": 0,
- "75_percentile": 0,
- "std_dev": 0,
- "95_percentile": 0,
- "avg": 0
- },
- "python.gc.collection.count2": {
- "value": 10
- },
- "python.gc.collection.count0": {
- "value": 10
- },
- "python.gc.collection.count1": {
- "value": 10
- },
- "python.multiprocessing.daemon": {
- "value": 0
- },
- "desktop.requests.active.count": {
- "count": 0
- }
- }
- """
|