# -*- coding: utf-8 -*-
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Process metrics."""

from __future__ import absolute_import
from __future__ import print_function

from functools import partial

import psutil  # pylint: disable=import-error

from chromite.lib import cros_logging as logging
from chromite.lib import metrics

logger = logging.getLogger(__name__)

_count_metric = metrics.GaugeMetric(
    'proc/count',
    description='Number of processes currently running.')
_cpu_percent_metric = metrics.GaugeMetric(
    'proc/cpu_percent',
    description='CPU usage percent of processes.')


def collect_proc_info():
  collector = _ProcessMetricsCollector()
  collector.collect()


class _ProcessMetricsCollector(object):
  """Class for collecting process metrics."""

  def __init__(self):
    self._metrics = [
        _ProcessMetric('apache',
                       test_func=partial(_is_process_name, 'apache2')),
        _ProcessMetric('autoserv',
                       test_func=_is_parent_autoserv),
        _ProcessMetric('getty',
                       test_func=partial(_is_process_name, 'getty')),
        _ProcessMetric('gs_offloader',
                       test_func=_is_gs_offloader),
        _ProcessMetric('job_aborter',
                       test_func=partial(_is_python_module,
                                         'lucifer.cmd.job_aborter')),
        _ProcessMetric('job_reporter',
                       test_func=partial(_is_python_module,
                                         'lucifer.cmd.job_reporter')),
        _ProcessMetric('lucifer',
                       test_func=partial(_is_process_name, 'lucifer')),
        _ProcessMetric('lxc-start',
                       test_func=partial(_is_process_name, 'lxc-start')),
        _ProcessMetric('lxc-attach',
                       test_func=partial(_is_process_name, 'lxc-attach')),
        _ProcessMetric('sysmon',
                       test_func=partial(_is_python_module,
                                         'chromite.scripts.sysmon')),
    ]
    self._other_metric = _ProcessMetric('other')

  def collect(self):
    for proc in psutil.process_iter():
      self._collect_proc(proc)
    self._flush()

  def _collect_proc(self, proc):
    for metric in self._metrics:
      if metric.add(proc):
        break
    else:
      self._other_metric.add(proc)

  def _flush(self):
    for metric in self._metrics:
      metric.flush()
    self._other_metric.flush()


class _ProcessMetric(object):
  """Class for gathering process metrics."""

  def __init__(self, process_name, test_func=lambda proc: True):
    """Initialize instance.

    process_name is used to identify the metric stream.

    test_func is a function called
    for each process.  If it returns True, the process is counted.  The
    default test is to count every process.
    """
    self._fields = {
        'process_name': process_name,
    }
    self._test_func = test_func
    self._count = 0
    self._cpu_percent = 0

  def add(self, proc):
    """Do metric collection for the given process.

    Returns True if the process was collected.
    """
    if not self._test_func(proc):
      return False
    self._count += 1
    self._cpu_percent += proc.cpu_percent()
    return True

  def flush(self):
    """Finish collection and send metrics."""
    _count_metric.set(self._count, fields=self._fields)
    self._count = 0
    _cpu_percent_metric.set(int(round(self._cpu_percent)), fields=self._fields)
    self._cpu_percent = 0


def _is_parent_autoserv(proc):
  """Return whether proc is a parent (not forked) autoserv process."""
  return _is_autoserv(proc) and not _is_autoserv(proc.parent())


def _is_autoserv(proc):
  """Return whether proc is an autoserv process."""
  # This relies on the autoserv script being run directly.  The script should
  # be named autoserv exactly and start with a shebang that is /usr/bin/python,
  # NOT /bin/env
  return _is_process_name('autoserv', proc)


def _is_gs_offloader(proc):
  """Return whether proc is a gs_offloader process."""
  cmdline = proc.cmdline()
  return (len(cmdline) >= 2
          and cmdline[0].endswith('python')
          and cmdline[1].endswith('gs_offloader.py'))


def _is_python_module(module, proc):
  """Return whether proc is a process running a Python module."""
  cmdline = proc.cmdline()
  return (cmdline and
          cmdline[0].endswith('python') and
          cmdline[1:3] == ['-m', module])


def _is_process_name(name, proc):
  """Return whether process proc is named name."""
  return proc.name() == name
