diff --git a/.gitignore b/.gitignore index 2eb6e784..44a7b3d4 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ htmlcov .vscode/ .pytest_cache pip-wheel-metadata +docs/source/reference/metrics.rst diff --git a/docs/Makefile b/docs/Makefile index b20dc238..5e61789e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -48,6 +48,7 @@ help: @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" @echo " spelling to run spell check on documentation" + @echo " metrics to generate documentation for metrics by inspecting the source code" clean: rm -rf $(BUILDDIR)/* @@ -60,7 +61,12 @@ rest-api: source/_static/rest-api/index.html source/_static/rest-api/index.html: rest-api.yml node_modules npm run rest-api -html: rest-api +metrics: source/reference/metrics.rst + +source/reference/metrics.rst: generate-metrics.py + python3 generate-metrics.py + +html: rest-api metrics $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/docs/generate-metrics.py b/docs/generate-metrics.py new file mode 100644 index 00000000..81304bef --- /dev/null +++ b/docs/generate-metrics.py @@ -0,0 +1,57 @@ +import os +from os.path import join + +from pytablewriter import RstSimpleTableWriter +from pytablewriter.style import Style + +import jupyterhub.metrics + +HERE = os.path.abspath(os.path.dirname(__file__)) + + +class Generator: + @classmethod + def create_writer(cls, table_name, headers, values): + writer = RstSimpleTableWriter() + writer.table_name = table_name + writer.headers = headers + writer.value_matrix = values + writer.margin = 1 + [writer.set_style(header, Style(align="center")) for header in headers] + return writer + + def _parse_metrics(self): + table_rows = [] + for name in dir(jupyterhub.metrics): + obj = getattr(jupyterhub.metrics, name) + if obj.__class__.__module__.startswith('prometheus_client.'): + for metric in obj.describe(): + table_rows.append([metric.type, metric.name, metric.documentation]) + return table_rows + + def prometheus_metrics(self): + generated_directory = f"{HERE}/source/reference" + if not os.path.exists(generated_directory): + os.makedirs(generated_directory) + + filename = f"{generated_directory}/metrics.rst" + table_name = "" + headers = ["Type", "Name", "Description"] + values = self._parse_metrics() + writer = self.create_writer(table_name, headers, values) + + title = "List of Prometheus Metrics" + underline = "============================" + content = f"{title}\n{underline}\n{writer.dumps()}" + with open(filename, 'w') as f: + f.write(content) + print(f"Generated {filename}.") + + +def main(): + doc_generator = Generator() + doc_generator.prometheus_metrics() + + +if __name__ == "__main__": + main() diff --git a/docs/requirements.txt b/docs/requirements.txt index 472fcc28..2d9da795 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,6 +5,7 @@ alabaster_jupyterhub # 0.1.0 released. https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip pydata-sphinx-theme +pytablewriter>=0.56 recommonmark>=0.6 sphinx-copybutton sphinx-jsonschema diff --git a/docs/source/conf.py b/docs/source/conf.py index 63f758c9..e1e09b3e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -217,10 +217,10 @@ intersphinx_mapping = {'https://docs.python.org/3/': None} on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if on_rtd: # readthedocs.org uses their theme by default, so no need to specify it - # build rest-api, since RTD doesn't run make + # build both metrics and rest-api, since RTD doesn't run make from subprocess import check_call as sh - sh(['make', 'rest-api'], cwd=docs) + sh(['make', 'metrics', 'rest-api'], cwd=docs) # -- Spell checking ------------------------------------------------------- diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst index 4008a723..ed478fa1 100644 --- a/docs/source/reference/index.rst +++ b/docs/source/reference/index.rst @@ -16,6 +16,7 @@ what happens under-the-hood when you deploy and configure your JupyterHub. proxy separate-proxy rest + monitoring database templates ../events/index diff --git a/docs/source/reference/monitoring.rst b/docs/source/reference/monitoring.rst new file mode 100644 index 00000000..774656ec --- /dev/null +++ b/docs/source/reference/monitoring.rst @@ -0,0 +1,20 @@ +Monitoring +========== + +This section covers details on monitoring the state of your JupyterHub installation. + +JupyterHub expose the ``/metrics`` endpoint that returns text describing its current +operational state formatted in a way `Prometheus `_ understands. + +Prometheus is a separate open source tool that can be configured to repeatedly poll +JupyterHub's ``/metrics`` endpoint to parse and save its current state. + +By doing so, Prometheus can describe JupyterHub's evolving state over time. +This evolving state can then be accessed through Prometheus that expose its underlying +storage to those allowed to access it, and be presented with dashboards by a +tool like `Grafana `_. + +.. toctree:: + :maxdepth: 2 + + metrics