Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Batch 2] Notebook PR Ports. #97

Merged
merged 9 commits into from
Sep 25, 2019
7 changes: 5 additions & 2 deletions jupyter_server/base/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,11 @@ def finish(self, *args, **kwargs):
return super(APIHandler, self).finish(*args, **kwargs)

def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Headers',
'accept, content-type, authorization, x-xsrftoken')
if 'Access-Control-Allow-Headers' in self.settings.get('headers', {}):
self.set_header('Access-Control-Allow-Headers', self.settings['headers']['Access-Control-Allow-Headers'])
else:
self.set_header('Access-Control-Allow-Headers',
'accept, content-type, authorization, x-xsrftoken')
self.set_header('Access-Control-Allow-Methods',
'GET, PUT, POST, PATCH, DELETE, OPTIONS')

Expand Down
3 changes: 2 additions & 1 deletion jupyter_server/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

import json
from tornado.log import access_log
from .metrics import prometheus_log_method
from .prometheus.log_functions import prometheus_log_method


def log_request(handler):
"""log a bit more information about each request than tornado's default
Expand Down
15 changes: 1 addition & 14 deletions jupyter_server/metrics.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
"""
Prometheus metrics exported by Jupyter Notebook Server
from ..prometheus.metrics import HTTP_REQUEST_DURATION_SECONDS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it really be a .. here?


Read https://prometheus.io/docs/practices/naming/ for naming
conventions for metrics & labels.
"""

from prometheus_client import Histogram

# This is a fairly standard name for HTTP duration latency reporting
HTTP_REQUEST_DURATION_SECONDS = Histogram(
'http_request_duration_seconds',
'duration in seconds for all HTTP requests',
['method', 'handler', 'status_code'],
)

def prometheus_log_method(handler):
"""
Expand Down
Empty file.
24 changes: 24 additions & 0 deletions jupyter_server/prometheus/log_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from notebook.prometheus.metrics import HTTP_REQUEST_DURATION_SECONDS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notebook

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #98.



def prometheus_log_method(handler):
"""
Tornado log handler for recording RED metrics.

We record the following metrics:
Rate - the number of requests, per second, your services are serving.
Errors - the number of failed requests per second.
Duration - The amount of time each request takes expressed as a time interval.

We use a fully qualified name of the handler as a label,
rather than every url path to reduce cardinality.

This function should be either the value of or called from a function
that is the 'log_function' tornado setting. This makes it get called
at the end of every request, allowing us to record the metrics we need.
"""
HTTP_REQUEST_DURATION_SECONDS.labels(
method=handler.request.method,
handler='{}.{}'.format(handler.__class__.__module__, type(handler).__name__),
status_code=handler.get_status()
).observe(handler.request.request_time())
27 changes: 27 additions & 0 deletions jupyter_server/prometheus/metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Prometheus metrics exported by Jupyter Notebook Server

Read https://prometheus.io/docs/practices/naming/ for naming
conventions for metrics & labels.
"""


from prometheus_client import Histogram, Gauge


HTTP_REQUEST_DURATION_SECONDS = Histogram(
'http_request_duration_seconds',
'duration in seconds for all HTTP requests',
['method', 'handler', 'status_code'],
)

TERMINAL_CURRENTLY_RUNNING_TOTAL = Gauge(
'terminal_currently_running_total',
'counter for how many terminals are running',
)

KERNEL_CURRENTLY_RUNNING_TOTAL = Gauge(
'kernel_currently_running_total',
'counter for how many kernels are running labeled by type',
['type']
)
2 changes: 1 addition & 1 deletion jupyter_server/services/kernels/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def _finish_kernel_info(self, info):
protocol_version = info.get('protocol_version', client_protocol_version)
if protocol_version != client_protocol_version:
self.session.adapt_version = int(protocol_version.split('.')[0])
self.log.info("Adapting to protocol v%s for kernel %s", protocol_version, self.kernel_id)
self.log.info("Adapting from protocol version {protocol_version} (kernel {kernel_id}) to {client_protocol_version} (client).".format(protocol_version=protocol_version, kernel_id=self.kernel_id, client_protocol_version=client_protocol_version))
if not self._kernel_info_future.done():
self._kernel_info_future.set_result(info)

Expand Down
21 changes: 19 additions & 2 deletions jupyter_server/services/kernels/kernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from jupyter_server._tz import utcnow, isoformat
from ipython_genutils.py3compat import getcwd

from notebook.prometheus.metrics import KERNEL_CURRENTLY_RUNNING_TOTAL
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notebook?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#98



class MappingKernelManager(MultiKernelManager):
"""A KernelManager that handles
Expand Down Expand Up @@ -178,6 +180,13 @@ def start_kernel(self, kernel_id=None, path=None, **kwargs):
lambda : self._handle_kernel_died(kernel_id),
'dead',
)

# Increase the metric of number of kernels running
# for the relevant kernel type by 1
KERNEL_CURRENTLY_RUNNING_TOTAL.labels(
type=self._kernels[kernel_id].kernel_name
).inc()

else:
self._check_kernel_id(kernel_id)
self.log.info("Using existing kernel: %s" % kernel_id)
Expand Down Expand Up @@ -282,11 +291,19 @@ def shutdown_kernel(self, kernel_id, now=False):
"""Shutdown a kernel by kernel_id"""
self._check_kernel_id(kernel_id)
kernel = self._kernels[kernel_id]
kernel._activity_stream.close()
kernel._activity_stream = None
if kernel._activity_stream:
kernel._activity_stream.close()
kernel._activity_stream = None
self.stop_buffering(kernel_id)
self._kernel_connections.pop(kernel_id, None)
self.last_kernel_activity = utcnow()

# Decrease the metric of number of kernels
# running for the relevant kernel type by 1
KERNEL_CURRENTLY_RUNNING_TOTAL.labels(
type=self._kernels[kernel_id].kernel_name
).dec()

return super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now)

def restart_kernel(self, kernel_id):
Expand Down
22 changes: 18 additions & 4 deletions jupyter_server/services/nbconvert/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,32 @@

from ...base.handlers import APIHandler


class NbconvertRootHandler(APIHandler):

@web.authenticated
def get(self):
try:
from nbconvert.exporters.export import exporter_map
from nbconvert.exporters import base
except ImportError as e:
raise web.HTTPError(500, "Could not import nbconvert: %s" % e)
res = {}
for format, exporter in exporter_map.items():
res[format] = info = {}
info['output_mimetype'] = exporter.output_mimetype
exporters = base.get_export_names()
for exporter_name in exporters:
try:
exporter_class = base.get_exporter(exporter_name)
except ValueError:
# I think the only way this will happen is if the entrypoint
# is uninstalled while this method is running
continue
# XXX: According to the docs, it looks like this should be set to None
# if the exporter shouldn't be exposed to the front-end and a friendly
# name if it should. However, none of the built-in exports have it defined.
# if not exporter_class.export_from_notebook:
# continue
res[exporter_name] = {
"output_mimetype": exporter_class.output_mimetype,
}

self.finish(json.dumps(res))

Expand Down
16 changes: 15 additions & 1 deletion jupyter_server/terminal/api_handlers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
from tornado import web, gen
from ..base.handlers import APIHandler
from ..utils import url_path_join
from ..prometheus.metrics import TERMINAL_CURRENTLY_RUNNING_TOTAL



class TerminalRootHandler(APIHandler):
Expand All @@ -12,12 +13,20 @@ def get(self):
terms = [{'name': name} for name in tm.terminals]
self.finish(json.dumps(terms))

# Update the metric below to the length of the list 'terms'
TERMINAL_CURRENTLY_RUNNING_TOTAL.set(
len(terms)
)

@web.authenticated
def post(self):
"""POST /terminals creates a new terminal and redirects to it"""
name, _ = self.terminal_manager.new_named_terminal()
self.finish(json.dumps({'name': name}))

# Increase the metric by one because a new terminal was created
TERMINAL_CURRENTLY_RUNNING_TOTAL.inc()


class TerminalHandler(APIHandler):
SUPPORTED_METHODS = ('GET', 'DELETE')
Expand All @@ -38,5 +47,10 @@ def delete(self, name):
yield tm.terminate(name, force=True)
self.set_status(204)
self.finish()

# Decrease the metric below by one
# because a terminal has been shutdown
TERMINAL_CURRENTLY_RUNNING_TOTAL.dec()

else:
raise web.HTTPError(404, "Terminal not found: %r" % name)