diff --git a/jupyter_server/prometheus/metrics.py b/jupyter_server/prometheus/metrics.py index 1a02f86209..0afcf6e23e 100644 --- a/jupyter_server/prometheus/metrics.py +++ b/jupyter_server/prometheus/metrics.py @@ -5,19 +5,35 @@ conventions for metrics & labels. """ +from prometheus_client import Gauge, Histogram, Info + +from jupyter_server._version import version_info as server_version_info + try: - # Jupyter Notebook also defines these metrics. Re-defining them results in a ValueError. - # Try to de-duplicate by using the ones in Notebook if available. + from notebook._version import version_info as notebook_version_info +except ImportError: + notebook_version_info = None + + +if ( + notebook_version_info is not None # No notebook package found + and notebook_version_info < (7,) # Notebook package found, is version 6 + # Notebook package found, but its version is the same as jupyter_server + # version. This means some package (looking at you, nbclassic) has shimmed + # the notebook package to instead be imports from the jupyter_server package. + # In such cases, notebook.prometheus.metrics is actually *this file*, so + # trying to import it will cause a circular import. So we don't. + and notebook_version_info != server_version_info +): + # Jupyter Notebook v6 also defined these metrics. Re-defining them results in a ValueError, + # so we simply re-export them if we are co-existing with the notebook v6 package. # See https://github.com/jupyter/jupyter_server/issues/209 from notebook.prometheus.metrics import ( HTTP_REQUEST_DURATION_SECONDS, KERNEL_CURRENTLY_RUNNING_TOTAL, TERMINAL_CURRENTLY_RUNNING_TOTAL, ) - -except ImportError: - from prometheus_client import Gauge, Histogram - +else: HTTP_REQUEST_DURATION_SECONDS = Histogram( "http_request_duration_seconds", "duration in seconds for all HTTP requests", @@ -35,9 +51,12 @@ ["type"], ) +# New prometheus metrics that do not exist in notebook v6 go here +SERVER_INFO = Info("jupyter_server", "Jupyter Server Version information") __all__ = [ "HTTP_REQUEST_DURATION_SECONDS", "TERMINAL_CURRENTLY_RUNNING_TOTAL", "KERNEL_CURRENTLY_RUNNING_TOTAL", + "SERVER_INFO", ] diff --git a/jupyter_server/serverapp.py b/jupyter_server/serverapp.py index bf375cbef6..26499c410e 100644 --- a/jupyter_server/serverapp.py +++ b/jupyter_server/serverapp.py @@ -110,6 +110,7 @@ GatewaySessionManager, ) from jupyter_server.log import log_request +from jupyter_server.prometheus.metrics import SERVER_INFO from jupyter_server.services.config import ConfigManager from jupyter_server.services.contents.filemanager import ( AsyncFileContentsManager, @@ -2696,6 +2697,12 @@ def _init_asyncio_patch() -> None: # prefer Selector to Proactor for tornado + pyzmq asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy()) + def init_metrics(self) -> None: + """ + Initialize any prometheus metrics that need to be set up on server startup + """ + SERVER_INFO.info({"version": __version__}) + @catch_config_error def initialize( self, @@ -2763,6 +2770,7 @@ def initialize( self.load_server_extensions() self.init_mime_overrides() self.init_shutdown_no_activity() + self.init_metrics() if new_httpserver: self.init_httpserver()