├── .flake8 ├── .github └── workflows │ ├── build.yml │ ├── check-release.yml │ ├── enforce-label.yml │ ├── lint.yml │ ├── prep-release.yml │ ├── publish-changelog.yml │ ├── publish-release.yml │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierignore ├── .travis.yml ├── .yarnrc.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RELEASE.md ├── binder ├── environment.yml └── postBuild ├── doc ├── kernel-usage-limited-info.png ├── kernel-usage.png ├── settings.png ├── statusbar-cpu.png ├── statusbar-warn.png ├── statusbar.png ├── statusbar_disk.png └── topbar.gif ├── install.json ├── jupyter-config ├── jupyter_notebook_config.d │ └── jupyter_resource_usage.json ├── jupyter_server_config.d │ └── jupyter_resource_usage.json └── nbconfig │ └── notebook.d │ └── jupyter_resource_usage.json ├── jupyter_resource_usage ├── __init__.py ├── _version.py ├── api.py ├── config.py ├── metrics.py ├── prometheus.py ├── server_extension.py ├── static │ └── main.js ├── tests │ ├── __init__.py │ └── test_basic.py └── utils.py ├── lerna.json ├── package.json ├── packages └── labextension │ ├── package.json │ ├── schema │ └── topbar-item.json │ ├── src │ ├── cpuView.tsx │ ├── diskView.tsx │ ├── format.ts │ ├── handler.ts │ ├── index.ts │ ├── indicator.tsx │ ├── memoryView.tsx │ ├── model.ts │ ├── panel.ts │ ├── resourceUsage.tsx │ ├── svg.d.ts │ ├── text.ts │ ├── tracker.ts │ ├── types.ts │ ├── useInterval.ts │ └── widget.tsx │ ├── style │ ├── base.css │ ├── index.css │ ├── index.js │ └── tachometer.svg │ └── tsconfig.json ├── pyproject.toml ├── setup.py └── yarn.lock /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length=200 3 | # Ignore style and complexity 4 | # E: style errors 5 | # W: style warnings 6 | # F401: module imported but unused 7 | # F811: redefinition of unused `name` from line `N` 8 | # F841: local variable assigned but never used 9 | ignore = E, C, W, F401, F403, F811, F841, E402, I100, I101, D400 10 | exclude = 11 | jupyter-resource-usage/tests, 12 | helm-chart, 13 | hooks, 14 | setup.py, 15 | statuspage, 16 | versioneer.py 17 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: '*' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Base Setup 20 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 21 | 22 | - name: Install dependencies 23 | run: python -m pip install jupyterlab~=4.0 nbclassic~=1.0 24 | 25 | - name: Install the extension 26 | run: | 27 | python -m pip install . 28 | jupyter server extension enable --py jupyter_resource_usage --sys-prefix 29 | jupyter nbclassic-serverextension enable --py jupyter_resource_usage --sys-prefix 30 | jupyter nbclassic-extension install --py jupyter_resource_usage --sys-prefix 31 | jupyter nbclassic-extension enable --py jupyter_resource_usage --sys-prefix 32 | 33 | - name: Check the server, classic and lab extensions are installed 34 | run: | 35 | jupyter server extension list 2>&1 | grep -ie "jupyter_resource_usage.*enabled" 36 | jupyter nbclassic-serverextension list 2>&1 | grep -ie "jupyter_resource_usage.*enabled" 37 | jupyter nbclassic-extension list 2>&1 | grep -ie "jupyter_resource_usage/main.*enabled" 38 | jupyter labextension list 39 | jupyter labextension list 2>&1 | grep -ie "@jupyter-server/resource-usage.*OK" 40 | python -m jupyterlab.browser_check 41 | -------------------------------------------------------------------------------- /.github/workflows/check-release.yml: -------------------------------------------------------------------------------- 1 | name: Check Release 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | pull_request: 7 | branches: 8 | - '*' 9 | 10 | permissions: 11 | contents: write 12 | 13 | jobs: 14 | check_release: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 19 | - name: Check Release 20 | uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 21 | with: 22 | token: ${{ secrets.GITHUB_TOKEN }} 23 | - name: Upload Distributions 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: jupyter-resource-usage-releaser-dist-${{ github.run_number }} 27 | path: .jupyter_releaser_checkout/dist 28 | -------------------------------------------------------------------------------- /.github/workflows/enforce-label.yml: -------------------------------------------------------------------------------- 1 | name: Enforce PR label 2 | 3 | on: 4 | pull_request: 5 | types: [labeled, unlabeled, opened, edited, synchronize] 6 | jobs: 7 | enforce-label: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | pull-requests: write 11 | steps: 12 | - name: enforce-triage-label 13 | uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 14 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | - name: Base Setup 19 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip black jupyterlab~=4.0 24 | 25 | - name: Lint Python 26 | run: | 27 | black --check . 28 | 29 | - name: Lint JS 30 | run: | 31 | jlpm 32 | jlpm run lint:check 33 | -------------------------------------------------------------------------------- /.github/workflows/prep-release.yml: -------------------------------------------------------------------------------- 1 | name: "Step 1: Prep Release" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version_spec: 6 | description: "New Version Specifier" 7 | default: "next" 8 | required: false 9 | branch: 10 | description: "The branch to target" 11 | required: false 12 | post_version_spec: 13 | description: "Post Version Specifier" 14 | required: false 15 | silent: 16 | description: "Set a placeholder in the changelog and don't publish the release." 17 | required: false 18 | type: boolean 19 | since: 20 | description: "Use PRs with activity since this date or git reference" 21 | required: false 22 | since_last_stable: 23 | description: "Use PRs with activity since the last stable git tag" 24 | required: false 25 | type: boolean 26 | jobs: 27 | prep_release: 28 | runs-on: ubuntu-latest 29 | permissions: 30 | contents: write 31 | steps: 32 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 33 | 34 | - name: Prep Release 35 | id: prep-release 36 | uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 37 | with: 38 | token: ${{ secrets.GITHUB_TOKEN }} 39 | version_spec: ${{ github.event.inputs.version_spec }} 40 | silent: ${{ github.event.inputs.silent }} 41 | post_version_spec: ${{ github.event.inputs.post_version_spec }} 42 | target: ${{ github.event.inputs.target }} 43 | branch: ${{ github.event.inputs.branch }} 44 | since: ${{ github.event.inputs.since }} 45 | since_last_stable: ${{ github.event.inputs.since_last_stable }} 46 | 47 | - name: "** Next Step **" 48 | run: | 49 | echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}" 50 | -------------------------------------------------------------------------------- /.github/workflows/publish-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Publish Changelog" 2 | on: 3 | release: 4 | types: [published] 5 | 6 | workflow_dispatch: 7 | inputs: 8 | branch: 9 | description: "The branch to target" 10 | required: false 11 | 12 | jobs: 13 | publish_changelog: 14 | runs-on: ubuntu-latest 15 | environment: release 16 | steps: 17 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 18 | 19 | - uses: actions/create-github-app-token@v1 20 | id: app-token 21 | with: 22 | app-id: ${{ vars.APP_ID }} 23 | private-key: ${{ secrets.APP_PRIVATE_KEY }} 24 | 25 | - name: Publish changelog 26 | id: publish-changelog 27 | uses: jupyter-server/jupyter_releaser/.github/actions/publish-changelog@v2 28 | with: 29 | token: ${{ steps.app-token.outputs.token }} 30 | branch: ${{ github.event.inputs.branch }} 31 | 32 | - name: "** Next Step **" 33 | run: | 34 | echo "Merge the changelog update PR: ${{ steps.publish-changelog.outputs.pr_url }}" 35 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: "Step 2: Publish Release" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | branch: 6 | description: "The target branch" 7 | required: false 8 | release_url: 9 | description: "The URL of the draft GitHub release" 10 | required: false 11 | steps_to_skip: 12 | description: "Comma separated list of steps to skip" 13 | required: false 14 | 15 | jobs: 16 | publish_release: 17 | runs-on: ubuntu-latest 18 | environment: release 19 | permissions: 20 | id-token: write 21 | steps: 22 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 23 | 24 | - uses: actions/create-github-app-token@v1 25 | id: app-token 26 | with: 27 | app-id: ${{ vars.APP_ID }} 28 | private-key: ${{ secrets.APP_PRIVATE_KEY }} 29 | 30 | - name: Populate Release 31 | id: populate-release 32 | uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 33 | with: 34 | token: ${{ steps.app-token.outputs.token }} 35 | branch: ${{ github.event.inputs.branch }} 36 | release_url: ${{ github.event.inputs.release_url }} 37 | steps_to_skip: ${{ github.event.inputs.steps_to_skip }} 38 | 39 | - name: Finalize Release 40 | id: finalize-release 41 | env: 42 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 43 | uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2 44 | with: 45 | token: ${{ steps.app-token.outputs.token }} 46 | release_url: ${{ steps.populate-release.outputs.release_url }} 47 | 48 | - name: "** Next Step **" 49 | if: ${{ success() }} 50 | run: | 51 | echo "Verify the final release" 52 | echo ${{ steps.finalize-release.outputs.release_url }} 53 | 54 | - name: "** Failure Message **" 55 | if: ${{ failure() }} 56 | run: | 57 | echo "Failed to Publish the Draft Release Url:" 58 | echo ${{ steps.populate-release.outputs.release_url }} 59 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | os: [ubuntu-latest, macos-latest, windows-latest] 16 | python-version: ["3.8", "3.11"] 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | 22 | - name: Base Setup 23 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 24 | 25 | - name: Install dependencies 26 | run: | 27 | python -m pip install -e ".[dev]" 28 | 29 | - name: Lint with flake8 30 | run: | 31 | python -m flake8 jupyter_resource_usage 32 | 33 | - name: Test with pytest 34 | run: | 35 | python -m pytest -vvv jupyter_resource_usage --cov=jupyter_resource_usage --junitxml=python_junit.xml --cov-report=xml --cov-branch 36 | 37 | check_links: 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v3 41 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 42 | - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | ### Python ### 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # Distribution / packaging 10 | .Python 11 | .direnv 12 | .envrc 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | *.ipynb 29 | MANIFEST 30 | 31 | # IDE and code editors 32 | *.iml 33 | .idea 34 | .vscode 35 | *.code-workspace 36 | .history 37 | 38 | # Labextension 39 | *.bundle.* 40 | lib/ 41 | node_modules/ 42 | *.egg-info/ 43 | .ipynb_checkpoints 44 | *.tsbuildinfo 45 | jupyter_resource_usage/labextension 46 | yarn-error.log 47 | .yarn/ 48 | .pnp* 49 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/reorder-python-imports 3 | rev: v3.12.0 4 | hooks: 5 | - id: reorder-python-imports 6 | language_version: python3 7 | - repo: https://github.com/psf/black 8 | rev: 24.2.0 9 | hooks: 10 | - id: black 11 | - repo: https://github.com/PyCQA/flake8 12 | rev: "7.0.0" 13 | hooks: 14 | - id: flake8 15 | - repo: https://github.com/pre-commit/pre-commit-hooks 16 | rev: v4.5.0 17 | hooks: 18 | - id: end-of-file-fixer 19 | - id: check-json 20 | - id: check-yaml 21 | exclude: ^helm-chart/nbviewer/templates/ 22 | - id: check-case-conflict 23 | - id: check-executables-have-shebangs 24 | - id: requirements-txt-fixer 25 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/node_modules 3 | **/lib 4 | **/package.json 5 | 6 | jupyter_resource_usage/labextension 7 | jupyter_resource_usage/static 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 3.7 5 | - 3.8 6 | 7 | before_install: 8 | - pip install --upgrade setuptools pip 9 | 10 | install: 11 | - pip install --editable . 12 | 13 | script: 14 | - python -m pytest -vvv jupyter-resource-usage 15 | 16 | 17 | jobs: 18 | include: 19 | - name: autoformatting check 20 | python: 3.6 21 | # NOTE: It does not suffice to override to: null, [], or [""]. Travis will 22 | # fall back to the default if we do. 23 | before_install: echo "Do nothing before install." 24 | install: pip install pre-commit 25 | script: 26 | - pre-commit run --all-files 27 | after_success: echo "Do nothing after success." 28 | after_failure: 29 | - | 30 | echo "You can install pre-commit hooks to automatically run formatting" 31 | echo "on each commit with:" 32 | echo " pre-commit install" 33 | echo "or you can run by hand on staged files with" 34 | echo " pre-commit run" 35 | echo "or after-the-fact on already committed files with" 36 | echo " pre-commit run --all-files" 37 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableImmutableInstalls: false 2 | nodeLinker: node-modules 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | 5 | ## 1.1.1 6 | 7 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@1.1.0...6d739a7cda47c1101f0c70e16806739cf6b0c575)) 8 | 9 | ### Bugs fixed 10 | 11 | - Fix typo in default username for jupyter [#239](https://github.com/jupyter-server/jupyter-resource-usage/pull/239) ([@evsasha](https://github.com/evsasha)) 12 | 13 | ### Maintenance and upkeep improvements 14 | 15 | - Update to `actions/upload-artifact@v4` [#241](https://github.com/jupyter-server/jupyter-resource-usage/pull/241) ([@jtpio](https://github.com/jtpio)) 16 | - Delete second copy of enforce-labels [#240](https://github.com/jupyter-server/jupyter-resource-usage/pull/240) ([@krassowski](https://github.com/krassowski)) 17 | 18 | ### Documentation improvements 19 | 20 | - Document `show_host_usage` configuration option in README [#218](https://github.com/jupyter-server/jupyter-resource-usage/pull/218) ([@pinksi](https://github.com/pinksi)) 21 | 22 | ### Contributors to this release 23 | 24 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2024-07-31&to=2025-02-04&type=c)) 25 | 26 | [@evsasha](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Aevsasha+updated%3A2024-07-31..2025-02-04&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2024-07-31..2025-02-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Akrassowski+updated%3A2024-07-31..2025-02-04&type=Issues) | [@pinksi](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apinksi+updated%3A2024-07-31..2025-02-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2024-07-31..2025-02-04&type=Issues) 27 | 28 | 29 | 30 | ## 1.1.0 31 | 32 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@1.0.2...41d88a2dc4bc9820f5801223d9830bd8f7c3d1d6)) 33 | 34 | ### Enhancements made 35 | 36 | - Add disk monitoring [#233](https://github.com/jupyter-server/jupyter-resource-usage/pull/233) ([@iandesj](https://github.com/iandesj)) 37 | 38 | ### Bugs fixed 39 | 40 | - Remove spurious close button on kernel usage panel [#228](https://github.com/jupyter-server/jupyter-resource-usage/pull/228) ([@krassowski](https://github.com/krassowski)) 41 | 42 | ### Contributors to this release 43 | 44 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2024-03-12&to=2024-07-31&type=c)) 45 | 46 | [@iandesj](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Aiandesj+updated%3A2024-03-12..2024-07-31&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Akrassowski+updated%3A2024-03-12..2024-07-31&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2024-03-12..2024-07-31&type=Issues) 47 | 48 | ## 1.0.2 49 | 50 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@1.0.1...498fd0c3eedccf37e7af8d344a2c26cf8a03ab80)) 51 | 52 | ### Maintenance and upkeep improvements 53 | 54 | - Update Release Scripts [#230](https://github.com/jupyter-server/jupyter-resource-usage/pull/230) ([@blink1073](https://github.com/blink1073)) 55 | 56 | ### Contributors to this release 57 | 58 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2023-08-29&to=2024-03-12&type=c)) 59 | 60 | [@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ablink1073+updated%3A2023-08-29..2024-03-12&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2023-08-29..2024-03-12&type=Issues) 61 | 62 | ## 1.0.1 63 | 64 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@1.0.0...bd0d80160d4e4588644e842e06a279442c245340)) 65 | 66 | ### Enhancements made 67 | 68 | - Adds custom config to show/hide host usage info [#210](https://github.com/jupyter-server/jupyter-resource-usage/pull/210) ([@pinksi](https://github.com/pinksi)) 69 | 70 | ### Maintenance and upkeep improvements 71 | 72 | - Add Notebook 7 to Binder [#208](https://github.com/jupyter-server/jupyter-resource-usage/pull/208) ([@jtpio](https://github.com/jtpio)) 73 | 74 | ### Contributors to this release 75 | 76 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2023-07-28&to=2023-08-29&type=c)) 77 | 78 | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2023-07-28..2023-08-29&type=Issues) | [@pinksi](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apinksi+updated%3A2023-07-28..2023-08-29&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2023-07-28..2023-08-29&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ayuvipanda+updated%3A2023-07-28..2023-08-29&type=Issues) 79 | 80 | ## 1.0.0 81 | 82 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.7.2...1cf0e15ed06ce37d8fd4883464beb902fb562d86)) 83 | 84 | ### Enhancements made 85 | 86 | - Integrate `jupyterlab-system-monitor` extension [#202](https://github.com/jupyter-server/jupyter-resource-usage/pull/202) ([@mahendrapaipuri](https://github.com/mahendrapaipuri)) 87 | 88 | ### Bugs fixed 89 | 90 | - Handle `currentWidget` in `KernelWidgetTracker` [#206](https://github.com/jupyter-server/jupyter-resource-usage/pull/206) ([@jtpio](https://github.com/jtpio)) 91 | - Stop all channels to allow ZMQContext to properly cleanup between calls [#183](https://github.com/jupyter-server/jupyter-resource-usage/pull/183) ([@Zsailer](https://github.com/Zsailer)) 92 | 93 | ### Maintenance and upkeep improvements 94 | 95 | - Make `IStatusBar` optional for `resourceStatusPlugin` [#207](https://github.com/jupyter-server/jupyter-resource-usage/pull/207) ([@mahendrapaipuri](https://github.com/mahendrapaipuri)) 96 | - Require Python 3.8+ [#201](https://github.com/jupyter-server/jupyter-resource-usage/pull/201) ([@jtpio](https://github.com/jtpio)) 97 | - Bump word-wrap from 1.2.3 to 1.2.4 [#200](https://github.com/jupyter-server/jupyter-resource-usage/pull/200) ([@dependabot](https://github.com/dependabot)) 98 | - Bump semver from 5.7.1 to 5.7.2 [#198](https://github.com/jupyter-server/jupyter-resource-usage/pull/198) ([@dependabot](https://github.com/dependabot)) 99 | - Update to Jupyterlab 4 [#195](https://github.com/jupyter-server/jupyter-resource-usage/pull/195) ([@jtpio](https://github.com/jtpio)) 100 | - chore: move `prettier` and `eslint` configuration under `package.json` [#188](https://github.com/jupyter-server/jupyter-resource-usage/pull/188) ([@SauravMaheshkar](https://github.com/SauravMaheshkar)) 101 | - Bump webpack from 5.75.0 to 5.76.1 [#184](https://github.com/jupyter-server/jupyter-resource-usage/pull/184) ([@dependabot](https://github.com/dependabot)) 102 | - Rename references from `master` to `main` [#179](https://github.com/jupyter-server/jupyter-resource-usage/pull/179) ([@jtpio](https://github.com/jtpio)) 103 | 104 | ### Documentation improvements 105 | 106 | - Update README and fix settings file [#205](https://github.com/jupyter-server/jupyter-resource-usage/pull/205) ([@mahendrapaipuri](https://github.com/mahendrapaipuri)) 107 | 108 | ### Contributors to this release 109 | 110 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2023-02-20&to=2023-07-28&type=c)) 111 | 112 | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2023-02-20..2023-07-28&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2023-02-20..2023-07-28&type=Issues) | [@mahendrapaipuri](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Amahendrapaipuri+updated%3A2023-02-20..2023-07-28&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2023-02-20..2023-07-28&type=Issues) | [@SauravMaheshkar](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3ASauravMaheshkar+updated%3A2023-02-20..2023-07-28&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2023-02-20..2023-07-28&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3AZsailer+updated%3A2023-02-20..2023-07-28&type=Issues) 113 | 114 | ## 0.7.2 115 | 116 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.7.1...143f4568643af18f668d6388fb65fff06695d58d)) 117 | 118 | ### Bugs fixed 119 | 120 | - Clear state when switching away, add blank state indicator [#178](https://github.com/jupyter-server/jupyter-resource-usage/pull/178) ([@krassowski](https://github.com/krassowski)) 121 | - async fixes in kernel usage handler [#177](https://github.com/jupyter-server/jupyter-resource-usage/pull/177) ([@minrk](https://github.com/minrk)) 122 | 123 | ### Maintenance and upkeep improvements 124 | 125 | ### Contributors to this release 126 | 127 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2023-02-06&to=2023-02-20&type=c)) 128 | 129 | [@Gsbreddy](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3AGsbreddy+updated%3A2023-02-06..2023-02-20&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2023-02-06..2023-02-20&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Akrassowski+updated%3A2023-02-06..2023-02-20&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Aminrk+updated%3A2023-02-06..2023-02-20&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2023-02-06..2023-02-20&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2023-02-06..2023-02-20&type=Issues) 130 | 131 | ## 0.7.1 132 | 133 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.7.0...dfef59b8aa27eb768eb9e70e849c832d2841e6e9)) 134 | 135 | ### Enhancements made 136 | 137 | - Use `pss` if available [#171](https://github.com/jupyter-server/jupyter-resource-usage/pull/171) ([@jtpio](https://github.com/jtpio)) 138 | 139 | ### Maintenance and upkeep improvements 140 | 141 | - Fix formatting [#174](https://github.com/jupyter-server/jupyter-resource-usage/pull/174) ([@jtpio](https://github.com/jtpio)) 142 | - Bump http-cache-semantics from 4.1.0 to 4.1.1 [#173](https://github.com/jupyter-server/jupyter-resource-usage/pull/173) ([@dependabot](https://github.com/dependabot)) 143 | - Migrate to `hatch` [#168](https://github.com/jupyter-server/jupyter-resource-usage/pull/168) ([@jtpio](https://github.com/jtpio)) 144 | - Bump json5 from 1.0.1 to 1.0.2 [#166](https://github.com/jupyter-server/jupyter-resource-usage/pull/166) ([@dependabot](https://github.com/dependabot)) 145 | 146 | ### Contributors to this release 147 | 148 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2023-01-06&to=2023-02-06&type=c)) 149 | 150 | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2023-01-06..2023-02-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2023-01-06..2023-02-06&type=Issues) 151 | 152 | ## 0.7.0 153 | 154 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.6.4...861eafdd88aba1c2c405a3a1ade0bd376ac322ff)) 155 | 156 | ### Enhancements made 157 | 158 | - Add support for kernel usage [#164](https://github.com/jupyter-server/jupyter-resource-usage/pull/164) ([@davidbrochart](https://github.com/davidbrochart)) 159 | 160 | ### Maintenance and upkeep improvements 161 | 162 | - Bump loader-utils from 1.4.1 to 1.4.2 [#158](https://github.com/jupyter-server/jupyter-resource-usage/pull/158) ([@dependabot](https://github.com/dependabot)) 163 | 164 | ### Contributors to this release 165 | 166 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2022-11-14&to=2023-01-06&type=c)) 167 | 168 | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adavidbrochart+updated%3A2022-11-14..2023-01-06&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2022-11-14..2023-01-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2022-11-14..2023-01-06&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Akrassowski+updated%3A2022-11-14..2023-01-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2022-11-14..2023-01-06&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2022-11-14..2023-01-06&type=Issues) 169 | 170 | ## 0.6.4 171 | 172 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.6.3...c355a2b5c57dc930ddb5e2b7b33ef85bcaee8f03)) 173 | 174 | ### Maintenance and upkeep improvements 175 | 176 | - Bump loader-utils from 1.4.0 to 1.4.1 [#157](https://github.com/jupyter-server/jupyter-resource-usage/pull/157) ([@dependabot](https://github.com/dependabot)) 177 | - Prep for releaser v2 [#154](https://github.com/jupyter-server/jupyter-resource-usage/pull/154) ([@blink1073](https://github.com/blink1073)) 178 | 179 | ### Contributors to this release 180 | 181 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2022-10-06&to=2022-11-14&type=c)) 182 | 183 | [@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ablink1073+updated%3A2022-10-06..2022-11-14&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2022-10-06..2022-11-14&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2022-10-06..2022-11-14&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2022-10-06..2022-11-14&type=Issues) 184 | 185 | ## 0.6.3 186 | 187 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.6.2...f2366db3a26109832ad0e2ff1f2a8d3488c9dee7)) 188 | 189 | ### Bugs fixed 190 | 191 | - Define \_jupyter_server_extension_paths for backward compatibility [#148](https://github.com/jupyter-server/jupyter-resource-usage/pull/148) ([@casparvl](https://github.com/casparvl)) 192 | - Fix update at zero cpu [#147](https://github.com/jupyter-server/jupyter-resource-usage/pull/147) ([@casparvl](https://github.com/casparvl)) 193 | 194 | ### Maintenance and upkeep improvements 195 | 196 | - Remove `prepare` script [#145](https://github.com/jupyter-server/jupyter-resource-usage/pull/145) ([@jtpio](https://github.com/jtpio)) 197 | - Bump terser from 5.10.0 to 5.15.0 [#141](https://github.com/jupyter-server/jupyter-resource-usage/pull/141) ([@dependabot](https://github.com/dependabot)) 198 | - Bump moment from 2.29.2 to 2.29.4 [#140](https://github.com/jupyter-server/jupyter-resource-usage/pull/140) ([@dependabot](https://github.com/dependabot)) 199 | 200 | ### Contributors to this release 201 | 202 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2022-08-24&to=2022-10-06&type=c)) 203 | 204 | [@casparvl](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Acasparvl+updated%3A2022-08-24..2022-10-06&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2022-08-24..2022-10-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2022-08-24..2022-10-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2022-08-24..2022-10-06&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2022-08-24..2022-10-06&type=Issues) 205 | 206 | ## 0.6.2 207 | 208 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/@jupyter-server/resource-usage@0.6.1...d6edf6a8a94b5740670368c6ad91299049e5a34f)) 209 | 210 | ### Enhancements made 211 | 212 | - Allow users to opt out of prometheus metrics [#124](https://github.com/jupyter-server/jupyter-resource-usage/pull/124) ([@dleen](https://github.com/dleen)) 213 | 214 | ### Maintenance and upkeep improvements 215 | 216 | - Fix lint configuration and failures [#138](https://github.com/jupyter-server/jupyter-resource-usage/pull/138) ([@kevin-bates](https://github.com/kevin-bates)) 217 | - [pre-commit.ci] pre-commit autoupdate [#137](https://github.com/jupyter-server/jupyter-resource-usage/pull/137) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 218 | - [pre-commit.ci] pre-commit autoupdate [#135](https://github.com/jupyter-server/jupyter-resource-usage/pull/135) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 219 | - Bump parse-url from 6.0.0 to 6.0.2 [#133](https://github.com/jupyter-server/jupyter-resource-usage/pull/133) ([@dependabot](https://github.com/dependabot)) 220 | - [pre-commit.ci] pre-commit autoupdate [#132](https://github.com/jupyter-server/jupyter-resource-usage/pull/132) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 221 | - [pre-commit.ci] pre-commit autoupdate [#131](https://github.com/jupyter-server/jupyter-resource-usage/pull/131) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 222 | - [pre-commit.ci] pre-commit autoupdate [#129](https://github.com/jupyter-server/jupyter-resource-usage/pull/129) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 223 | - Bump nanoid from 3.1.30 to 3.3.3 [#128](https://github.com/jupyter-server/jupyter-resource-usage/pull/128) ([@dependabot](https://github.com/dependabot)) 224 | - [pre-commit.ci] pre-commit autoupdate [#126](https://github.com/jupyter-server/jupyter-resource-usage/pull/126) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 225 | - Bump moment from 2.29.1 to 2.29.2 [#125](https://github.com/jupyter-server/jupyter-resource-usage/pull/125) ([@dependabot](https://github.com/dependabot)) 226 | - [pre-commit.ci] pre-commit autoupdate [#122](https://github.com/jupyter-server/jupyter-resource-usage/pull/122) ([@pre-commit-ci](https://github.com/pre-commit-ci)) 227 | - Bump minimist from 1.2.5 to 1.2.6 [#121](https://github.com/jupyter-server/jupyter-resource-usage/pull/121) ([@dependabot](https://github.com/dependabot)) 228 | - Bump url-parse from 1.5.3 to 1.5.10 [#120](https://github.com/jupyter-server/jupyter-resource-usage/pull/120) ([@dependabot](https://github.com/dependabot)) 229 | 230 | ### Documentation improvements 231 | 232 | - Point the Binder link to the default branch [#117](https://github.com/jupyter-server/jupyter-resource-usage/pull/117) ([@jtpio](https://github.com/jtpio)) 233 | 234 | ### Contributors to this release 235 | 236 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2021-12-06&to=2022-08-24&type=c)) 237 | 238 | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2021-12-06..2022-08-24&type=Issues) | [@dleen](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adleen+updated%3A2021-12-06..2022-08-24&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2021-12-06..2022-08-24&type=Issues) | [@kevin-bates](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Akevin-bates+updated%3A2021-12-06..2022-08-24&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Apre-commit-ci+updated%3A2021-12-06..2022-08-24&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2021-12-06..2022-08-24&type=Issues) 239 | 240 | ## 0.6.1 241 | 242 | ([Full Changelog](https://github.com/jupyter-server/jupyter-resource-usage/compare/0.6.0...42df870ca30c1373fd7c5e48b00d1bb3f383c10a)) 243 | 244 | ### Enhancements made 245 | 246 | - catch psutil exceptions [#113](https://github.com/jupyter-server/jupyter-resource-usage/pull/113) ([@jhgoebbert](https://github.com/jhgoebbert)) 247 | - Add CPU display to extension [#105](https://github.com/jupyter-server/jupyter-resource-usage/pull/105) ([@stevenstetzler](https://github.com/stevenstetzler)) 248 | 249 | ### Bugs fixed 250 | 251 | - Ensure we use backoff when request fails [#104](https://github.com/jupyter-server/jupyter-resource-usage/pull/104) ([@vidartf](https://github.com/vidartf)) 252 | 253 | ### Maintenance and upkeep improvements 254 | 255 | - Adopt the Jupyter Releaser, update Jupyter Packaging [#115](https://github.com/jupyter-server/jupyter-resource-usage/pull/115) ([@jtpio](https://github.com/jtpio)) 256 | 257 | ### Other merged PRs 258 | 259 | - Bump tar from 6.1.5 to 6.1.11 in /packages/labextension [#111](https://github.com/jupyter-server/jupyter-resource-usage/pull/111) ([@dependabot](https://github.com/dependabot)) 260 | - Bump url-parse from 1.5.1 to 1.5.3 in /packages/labextension [#110](https://github.com/jupyter-server/jupyter-resource-usage/pull/110) ([@dependabot](https://github.com/dependabot)) 261 | - Bump path-parse from 1.0.6 to 1.0.7 in /packages/labextension [#108](https://github.com/jupyter-server/jupyter-resource-usage/pull/108) ([@dependabot](https://github.com/dependabot)) 262 | - Bump tar from 6.1.0 to 6.1.5 in /packages/labextension [#106](https://github.com/jupyter-server/jupyter-resource-usage/pull/106) ([@dependabot](https://github.com/dependabot)) 263 | - Bump normalize-url from 4.5.0 to 4.5.1 in /packages/labextension [#103](https://github.com/jupyter-server/jupyter-resource-usage/pull/103) ([@dependabot](https://github.com/dependabot)) 264 | - Bump ws from 7.4.5 to 7.4.6 in /packages/labextension [#102](https://github.com/jupyter-server/jupyter-resource-usage/pull/102) ([@dependabot](https://github.com/dependabot)) 265 | - Update to 3.0.16 packages [#101](https://github.com/jupyter-server/jupyter-resource-usage/pull/101) ([@jtpio](https://github.com/jtpio)) 266 | - Update dependencies [#100](https://github.com/jupyter-server/jupyter-resource-usage/pull/100) ([@jtpio](https://github.com/jtpio)) 267 | - Bump lodash from 4.17.20 to 4.17.21 in /packages/labextension [#99](https://github.com/jupyter-server/jupyter-resource-usage/pull/99) ([@dependabot](https://github.com/dependabot)) 268 | - Bump hosted-git-info from 2.8.8 to 2.8.9 in /packages/labextension [#98](https://github.com/jupyter-server/jupyter-resource-usage/pull/98) ([@dependabot](https://github.com/dependabot)) 269 | - Add changelog for 0.6.0 [#96](https://github.com/jupyter-server/jupyter-resource-usage/pull/96) ([@jtpio](https://github.com/jtpio)) 270 | 271 | ### Contributors to this release 272 | 273 | ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter-resource-usage/graphs/contributors?from=2021-04-29&to=2021-12-06&type=c)) 274 | 275 | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Adependabot+updated%3A2021-04-29..2021-12-06&type=Issues) | [@jhgoebbert](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajhgoebbert+updated%3A2021-04-29..2021-12-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Ajtpio+updated%3A2021-04-29..2021-12-06&type=Issues) | [@stevenstetzler](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Astevenstetzler+updated%3A2021-04-29..2021-12-06&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Avidartf+updated%3A2021-04-29..2021-12-06&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter-resource-usage+involves%3Awelcome+updated%3A2021-04-29..2021-12-06&type=Issues) 276 | 277 | ## 0.6.0 278 | 279 | - `executor` as ApiHandle class attribute [\#95](https://github.com/jupyter-server/jupyter-resource-usage/pull/95) ([jtpio](https://github.com/jtpio)) 280 | - Update RELEASE.md [\#94](https://github.com/jupyter-server/jupyter-resource-usage/pull/94) ([jtpio](https://github.com/jtpio)) 281 | - Clarify notebook/jupyter_server usage [\#93](https://github.com/jupyter-server/jupyter-resource-usage/pull/93) ([fcollonval](https://github.com/fcollonval)) 282 | - Bump ssri from 8.0.0 to 8.0.1 in /packages/labextension [\#90](https://github.com/jupyter-server/jupyter-resource-usage/pull/90) ([dependabot[bot]](https://github.com/apps/dependabot)) 283 | - Update to JupyterLab 3.0 final packages [\#87](https://github.com/jupyter-server/jupyter-resource-usage/pull/87) ([jtpio](https://github.com/jtpio)) 284 | - Add instructions to install with conda [\#83](https://github.com/jupyter-server/jupyter-resource-usage/pull/83) ([jtpio](https://github.com/jtpio)) 285 | - Add Changelog for 0.5.1 [\#82](https://github.com/jupyter-server/jupyter-resource-usage/pull/82) ([jtpio](https://github.com/jtpio)) 286 | 287 | ## 0.5.1 288 | 289 | - Skip building js assets if they already exist: [#81](https://github.com/jupyter-server/jupyter-resource-usage/pull/81) 290 | 291 | ## 0.5.0 292 | 293 | The repository has now moved to the [`jupyter-server`](https://github.com/jupyter-server) organization on GitHub. 294 | 295 | It was also renamed to `jupyter-resource-usage`. 296 | 297 | To install the package with `pip`: 298 | 299 | ```bash 300 | pip install jupyter-resource-usage 301 | ``` 302 | 303 | ### Other changes 304 | 305 | - Add a JupyterLab extension for the memory usage status bar item: [#69](https://github.com/jupyter-server/jupyter-resource-usage/pull/69) 306 | - Drop the deprecated `/metrics` endpoint: [#77](https://github.com/jupyter-server/jupyter-resource-usage/pull/77) 307 | 308 | ### Migrating to 0.5.0 309 | 310 | For classic notebook users, there shouldn't be any major change or action to take. The classic notebook extension is still distributed with the Python package as before. 311 | 312 | For JupyterLab 2.x users you will still need to use the previous `nbresuse` package. See below for more information. 313 | 314 | For JupyterLab 3.x, the status bar item is now packaged in its own extension and distributed with the `jupyter-resource-usage` package. This means that a single `pip install jupyter-resource-usage` is enough to install the server extension, the classic notebook extension and the JupyterLab extension all at once. 315 | 316 | ## 0.4.0 317 | 318 | - Soft-deprecate `/metrics` endpoint: [#68](https://github.com/jupyter-server/jupyter-resource-usage/pull/68) 319 | - `nbresuse` now exposes a new endpoint: `/api/metrics/v1`: [#68](https://github.com/jupyter-server/jupyter-resource-usage/pull/68) 320 | 321 | ### Migrating to 0.4.0 322 | 323 | To upgrade to the latest version: 324 | 325 | ``` 326 | python -m pip install -U nbresuse 327 | ``` 328 | 329 | If you use the classic notebook, there shouldn't be anything to do. The classic notebook extension already uses the new endpoint and is automatically installed. 330 | 331 | If you use JupyterLab 2.x and want the memory usage indicator in the status bar to continue showing metrics: 332 | 333 |  334 | 335 | Two options: 336 | 337 | - continue using `nbresuse==0.3.6` instead of `0.4.0` 338 | - enable the deprecated `/metrics` endpoint with: 339 | 340 | ```bash 341 | jupyter lab --ResourceUseDisplay.disable_legacy_endpoint=False 342 | ``` 343 | 344 | ## 0.3.6 345 | 346 | - Fix handling of cpu percent in the API endpoint [#56](https://github.com/jupyter-server/jupyter-resource-usage/pull/56) 347 | - Added Binder [#53](https://github.com/jupyter-server/jupyter-resource-usage/pull/53) & RELEASE.md [#54](https://github.com/jupyter-server/jupyter-resource-usage/pull/54) 348 | 349 | ## 0.3.5 350 | 351 | - Adding support for jupyterlab statusbar-extension [#45](https://github.com/jupyter-server/jupyter-resource-usage/pull/45) [#36](https://github.com/jupyter-server/jupyter-resource-usage/issues/36) 352 | 353 | **Note**: this release restores the `/metrics` endpoint returning a JSON response, that was removed in `0.3.4`. 354 | 355 | ## 0.3.4 356 | 357 | - Autoformatting and documentation [#33](https://github.com/jupyter-server/jupyter-resource-usage/pull/33) 358 | - Add section about CPU usage to the README [#30](https://github.com/jupyter-server/jupyter-resource-usage/pull/30) 359 | - Make psutil optional dependency of NBResuse [#25](https://github.com/jupyter-server/jupyter-resource-usage/pull/25) 360 | - Report the memory usage metrics as prometheus metrics [#22](https://github.com/jupyter-server/jupyter-resource-usage/pull/22) 361 | 362 | **Note**: this release removed the `/metrics` endpoint that was returning a JSON response. As a result, JupyterLab does not display the memory usage indicator in the status bar with `nbresuse==0.3.4`. 363 | 364 | ## 0.3.3 365 | 366 | - Made memory limit possibly dynamic via passing a callable in the config. [#23](https://github.com/jupyter-server/jupyter-resource-usage/pull/23) 367 | - Track CPU usage [#21](https://github.com/jupyter-server/jupyter-resource-usage/pull/21) 368 | 369 | ## 0.3.2 370 | 371 | - Require authentication for /metrics API Handler [#18](https://github.com/jupyter-server/jupyter-resource-usage/pull/18) 372 | 373 | ## 0.3.1 374 | 375 | - Don't poll in background, since user does not see it [#15](https://github.com/jupyter-server/jupyter-resource-usage/pull/15) 376 | - Poll instantly once page is foregrounded [#15](https://github.com/jupyter-server/jupyter-resource-usage/pull/15) 377 | 378 | This should reduce the number of /metrics requests massively, with minimal interruption to user experience. 379 | 380 | ## 0.3.0 381 | 382 | - Automatically install & enable extensions [#9](https://github.com/jupyter-server/jupyter-resource-usage/pull/9) 383 | - Put nbextension / serverextension enables in different places 384 | - Put nbresuse js files in appropriate path 385 | 386 | ## 0.2.0 387 | 388 | - Change 'Mem' prefix in display to less cryptic 'Memory' 389 | - Fix primary screenshot to show memory limit too 390 | - Distribute static files via package_data [#1](https://github.com/jupyter-server/jupyter-resource-usage/pull/1) 391 | - Add screenshot for memory usage warning 392 | - Configurable memory usage warnings 393 | - More configurability via traitlets 394 | - Consolidate code into single file 395 | - Document memory limit behavior 396 | - Add CONTRIBUTING.md doc 397 | - Updated README 398 | 399 | ## 0.1.0 400 | 401 | - Initial Commits for memory usage display 402 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions to jupyter-resource-usage are highly welcome! As a [Jupyter](https://jupyter.org) project, 4 | you can follow the [Jupyter contributor guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html). 5 | 6 | Make sure to also follow [Project Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md) 7 | for a friendly and welcoming collaborative environment. 8 | 9 | ## Setting up a development environment 10 | 11 | We recommend using [pipenv](https://docs.pipenv.org/) to make development easier. 12 | 13 | Alternatively, you can also use `conda` or `mamba` to create new virtual environments. 14 | 15 | Clone the git repository: 16 | 17 | ```bash 18 | git clone https://github.com/jupyter-server/jupyter-resource-usage 19 | ``` 20 | 21 | Create an environment that will hold our dependencies: 22 | 23 | ```bash 24 | cd jupyter-resource-usage 25 | pipenv --python 3.6 26 | ``` 27 | 28 | With conda: 29 | 30 | ```bash 31 | conda create -n jupyter-resource-usage -c conda-forge python 32 | ``` 33 | 34 | Activate the virtual environment that pipenv created for us 35 | 36 | ```bash 37 | pipenv shell 38 | ``` 39 | 40 | With conda: 41 | 42 | ```bash 43 | conda activate jupyter-resource-usage 44 | ``` 45 | 46 | Do a dev install of jupyter-resource-usage and its dependencies 47 | 48 | ```bash 49 | pip install --editable .[dev] 50 | ``` 51 | 52 | Enable the server extension: 53 | 54 | ```bash 55 | jupyter serverextension enable --py jupyter_resource_usage --sys-prefix 56 | ``` 57 | 58 | _Note: if you're using Jupyter Server:_ 59 | 60 | ```bash 61 | jupyter server extension enable --py jupyter_resource_usage --sys-prefix 62 | ``` 63 | 64 | ## Classic notebook extension 65 | 66 | Install and enable the nbextension for use with Jupyter Classic Notebook. 67 | 68 | ```bash 69 | jupyter nbextension install --py jupyter_resource_usage --symlink --sys-prefix 70 | jupyter nbextension enable --py jupyter_resource_usage --sys-prefix 71 | ``` 72 | 73 | Start a Jupyter Notebook instance, open a new notebook and check out the memory usage in the top right! 74 | 75 | ```bash 76 | jupyter notebook 77 | ``` 78 | 79 | If you want to test the memory limit display functionality, you can do so by setting the `MEM_LIMIT` environment variable (in bytes) when starting `jupyter notebook`. 80 | 81 | ```bash 82 | MEM_LIMIT=$(expr 128 \* 1024 \* 1024) jupyter notebook 83 | ``` 84 | 85 | ## JupyterLab extension 86 | 87 | The JupyterLab extension for `jupyter-resource-usage` was bootstrapped from the [extension cookiecutter](https://github.com/jupyterlab/extension-cookiecutter-ts), and follows the common patterns and tooling for developing extensions. 88 | 89 | ```bash 90 | # activate the environment (conda, pipenv) 91 | 92 | # install the package in development mode 93 | python -m pip install -e ".[dev]" 94 | 95 | # link your development version of the extension with JupyterLab 96 | jupyter labextension develop . --overwrite 97 | 98 | # go to the labextension directory 99 | cd packages/labextension/ 100 | 101 | # Rebuild extension Typescript source after making changes 102 | jlpm run build 103 | ``` 104 | 105 | You can watch the source directory and run JupyterLab at the same time in different terminals to watch for changes in the extension's source and automatically rebuild the extension. 106 | 107 | ```bash 108 | # Watch the source directory in one terminal, automatically rebuilding when needed 109 | jlpm run watch 110 | # Run JupyterLab in another terminal 111 | jupyter lab 112 | ``` 113 | 114 | With the watch command running, every saved change will immediately be built locally and available in your running JupyterLab. Refresh JupyterLab to load the change in your browser (you may need to wait several seconds for the extension to be rebuilt). 115 | 116 | To check the extension is correctly installed, run: 117 | 118 | ```bash 119 | jupyter labextension list 120 | ``` 121 | 122 | It should show something like the following: 123 | 124 | ```bash 125 | JupyterLab v3.0.0 126 | /path/to/env/share/jupyter/labextensions 127 | jupyter-resource-usage v0.1.0 enabled OK 128 | ``` 129 | 130 | ## Which code creates what content 131 | 132 | The stats are created by the server-side code in `jupyter_resource_usage`. 133 | 134 | For the jupyterlab 4 / notebook 7 UIs, the code in `packages/labextension` creates and writes the content for both the statusbar and the topbar. 135 | 136 | The topbar is defined in the schema, whilst the contents of the statusbar is driven purely by the labextension code.... and labels are defined by their appropriate `*View.tsx` file 137 | 138 | ## pre-commit 139 | 140 | `jupyter-resource-usage` has adopted automatic code formatting so you shouldn't need to worry too much about your code style. 141 | As long as your code is valid, 142 | the pre-commit hook should take care of how it should look. Here is how to set up pre-commit hooks for automatic code formatting, etc. 143 | 144 | ```bash 145 | pre-commit install 146 | ``` 147 | 148 | You can also invoke the pre-commit hook manually at any time with 149 | 150 | ```bash 151 | pre-commit run 152 | ``` 153 | 154 | which should run any autoformatting on your code 155 | and tell you about any errors it couldn't fix automatically. 156 | You may also install [black integration](https://github.com/ambv/black#editor-integration) 157 | into your text editor to format code automatically. 158 | 159 | If you have already committed files before setting up the pre-commit 160 | hook with `pre-commit install`, you can fix everything up using 161 | `pre-commit run --all-files`. You need to make the fixing commit 162 | yourself after that. 163 | 164 | ## Tests 165 | 166 | It's a good idea to write tests to exercise any new features, 167 | or that trigger any bugs that you have fixed to catch regressions. `pytest` is used to run the test suite. You can run the tests with in the repo directory: 168 | 169 | ```bash 170 | python -m pytest -vvv jupyter_resource_usage 171 | ``` 172 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Yuvi Panda 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **[Installation](#installation)** | 2 | **[Configuration](#configuration)** | 3 | **[Resources Displayed](#resources-displayed)** | 4 | **[Contributing](#contributing)** 5 | 6 | # jupyter-resource-usage 7 | 8 |  9 | [](https://mybinder.org/v2/gh/jupyter-server/jupyter-resource-usage/main) 10 | [](https://pypi.python.org/pypi/jupyter-resource-usage) 11 | [](https://anaconda.org/conda-forge/jupyter-resource-usage) 12 | [](https://pypi.python.org/pypi/jupyter-resource-usage) 13 | [](https://github.com/jupyter-server/jupyter-resource-usage/issues) 14 | 15 |  16 | 17 | Jupyter Resource Usage is an extension for Jupyter Notebooks and JupyterLab that 18 | displays an indication of how much resources your current notebook server and 19 | its children (kernels, terminals, etc) are using. This is displayed in the 20 | status bar in the JupyterLab and notebook, refreshing every 5s. 21 | 22 | Kernel resource usage can be displayed in a sidebar for IPython kernels with 23 | [ipykernel](https://github.com/ipython/ipykernel) >= 6.11.0. 24 | 25 |  26 | 27 | The kernel usage is available for Notebook 7.x too which can be enabled at 28 | `View -> Right Sidebar -> Show Kernel Usage`. In the case of JupyterLab interface, it is 29 | enough to click `tachometer` icon on the right sidebar. 30 | 31 | The package provides an alternative frontend for the `jupyter-resource-usage` metrics: 32 | 33 |  34 | 35 | Previously, this extension used to be distributed with 36 | [jupyterlab-system-monitor](https://github.com/jtpio/jupyterlab-system-monitor) package. 37 | Starting from `1.0.0`, the alternative frontend has been integrated into the 38 | current repository. Check [Alternative frontend](#enable-alternative-frontend) section 39 | on how to enable and configure this alternative frontend. 40 | 41 | **Note** that for JupyterLab 3.x and 2.x, users should install the alternative frontend 42 | from [jupyterlab-system-monitor](https://github.com/jtpio/jupyterlab-system-monitor). 43 | 44 | ## Installation 45 | 46 | ### JupyterLab 4.x and Notebook 7.x 47 | 48 | You should install the latest version `>=1.0.0` for JupyterLab 4 compatability. 49 | 50 | ```bash 51 | pip install jupyter-resource-usage 52 | ``` 53 | 54 | Or with `conda`: 55 | 56 | ```bash 57 | conda install -c conda-forge jupyter-resource-usage 58 | ``` 59 | 60 | ### JupyterLab 3.x and Notebook 6.x 61 | 62 | You should pin the versions to `<1.0.0` 63 | 64 | ```bash 65 | pip install 'jupyter-resource-usage<1.0.0' 66 | ``` 67 | 68 | Or with `conda`: 69 | 70 | ```bash 71 | conda install -c conda-forge 'jupyter-resource-usage<1.0.0' 72 | ``` 73 | 74 | **If your notebook version is < 5.3**, you need to enable the extension manually. 75 | 76 | ``` 77 | jupyter serverextension enable --py jupyter_resource_usage --sys-prefix 78 | jupyter nbextension install --py jupyter_resource_usage --sys-prefix 79 | jupyter nbextension enable --py jupyter_resource_usage --sys-prefix 80 | ``` 81 | 82 | ## Configuration 83 | 84 | ### Memory Limit 85 | 86 | `jupyter-resource-usage` can display a memory limit (but not enforce it). You can set this 87 | in several ways: 88 | 89 | 1. `MEM_LIMIT` environment variable. This is set by [JupyterHub](https://github.com/jupyterhub/jupyterhub/) 90 | if using a spawner that supports it. 91 | 2. In the commandline when starting `jupyter notebook`, as `--ResourceUseDisplay.mem_limit`. 92 | 3. In your Jupyter notebook [traitlets](https://traitlets.readthedocs.io/en/stable/) config file 93 | 94 | The limit needs to be set as an integer in Bytes. 95 | 96 | ### Memory usage warning threshold 97 | 98 |  99 | 100 | The background of the resource display can be changed to red when the user is near a memory limit. 101 | The threshold for this warning can be configured as a fraction of the memory limit. 102 | 103 | If you want to flash the warning to the user when they are within 10% of the memory limit, you 104 | can set the parameter `--ResourceUseDisplay.mem_warning_threshold=0.1`. 105 | 106 | ### Host information 107 | 108 | If you want to hide host information from the Kernel Usage sidebar 109 | you can set `--ResourceUseDisplay.show_host_usage=False` to hide `Host CPU` and `Host Virtual Memory` information. 110 | The default is set as `True`, i.e. show all the information. 111 | 112 |  113 | 114 | ### CPU Usage 115 | 116 | `jupyter-resource-usage` can also track CPU usage and report a `cpu_percent` value as part of the `/api/metrics/v1` response. 117 | 118 | You can set the `cpu_limit` in several ways: 119 | 120 | 1. `CPU_LIMIT` environment variable. This is set by [JupyterHub](https://github.com/jupyterhub/jupyterhub/) 121 | if using a spawner that supports it. 122 | 2. In the command line when starting `jupyter notebook`, as `--ResourceUseDisplay.cpu_limit`. 123 | 3. In your Jupyter notebook [traitlets](https://traitlets.readthedocs.io/en/stable/) config file 124 | 125 | The limit corresponds to the number of cpus the user has access to, but does not enforce it. 126 | 127 | Additionally, you can set the `track_cpu_percent` trait to enable CPU usage tracking (disabled by default): 128 | 129 | ```python 130 | c = get_config() 131 | c.ResourceUseDisplay.track_cpu_percent = True 132 | ``` 133 | 134 | As a command line argument: 135 | 136 | ```bash 137 | jupyter notebook --ResourceUseDisplay.track_cpu_percent=True 138 | ``` 139 | 140 | When `track_cpu_percent` is set to `True`, status will report CPU utilisation along with 141 | memory: 142 | 143 |  144 | 145 | ### Disk [partition] Usage 146 | 147 | `jupyter-resource-usage` can also track disk usage [of a defined partition] and report the `total` and `used` values as part of the `/api/metrics/v1` response. 148 | 149 | You enable tracking by setting the `track_disk_usage` trait (disabled by default): 150 | 151 | ```python 152 | c = get_config() 153 | c.ResourceUseDisplay.track_disk_usage = True 154 | ``` 155 | 156 | The values are from the partition containing the folder in the trait `disk_path` (which defaults to `/home/jovyan`). If this path does not exist, disk usage information is omitted from the display. 157 | 158 | Mirroring CPU and Memory, the trait `disk_warning_threshold` signifies when to flag a usage warning, and like the others, it defaults to `0.1` (10% remaining) 159 | 160 |  161 | 162 | ### Disable Prometheus Metrics 163 | 164 | There is a [known bug](https://github.com/jupyter-server/jupyter-resource-usage/issues/123) with Prometheus metrics which 165 | causes "lag"/pauses in the UI. To workaround this you can disable Prometheus metric reporting using: 166 | 167 | ``` 168 | --ResourceUseDisplay.enable_prometheus_metrics=False 169 | ``` 170 | 171 | ## Enable alternative frontend 172 | 173 | By default, the alternative frontend is disabled. To enable it, users should go to 174 | `Settings -> Settings Editor -> Resource Usage Indicator` which will render following 175 | form 176 | 177 |  178 | 179 | By checking "Enable resource usage indicators" and refreshing the browser tab will 180 | render the alternative frontend in the topbar. 181 | 182 | Users can change the label and refresh rate for the alternative frontend using settings 183 | editor. 184 | 185 | (The vertical bars are included by default, to help separate the three indicators.) 186 | 187 | ## Resources Displayed 188 | 189 | Currently the server extension reports disk usage, memory usage and CPU usage. Other metrics will be added in the future as needed. 190 | 191 | Memory usage will show the PSS whenever possible (Linux only feature), and default to RSS otherwise. 192 | 193 | The notebook extension currently doesn't show CPU usage, only memory usage. 194 | 195 | ## Contributing 196 | 197 | If you would like to contribute to the project, please read the [`CONTRIBUTING.md`](CONTRIBUTING.md). The `CONTRIBUTING.md` file 198 | explains how to set up a development installation and how to run the test suite. 199 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Making a new release of `jupyter-resource-usage` 2 | 3 | ## Automated Releases with `jupyter_releaser` 4 | 5 | The recommended way to make a release is to use 6 | [`jupyter_releaser`](https://jupyter-releaser.readthedocs.io/en/latest/). 7 | -------------------------------------------------------------------------------- /binder/environment.yml: -------------------------------------------------------------------------------- 1 | name: jupyter-resource-usage 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python=3.10 6 | - jupyterlab=4 7 | - notebook=7 8 | - nodejs=18 9 | -------------------------------------------------------------------------------- /binder/postBuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | python -m pip install . --upgrade 5 | -------------------------------------------------------------------------------- /doc/kernel-usage-limited-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/kernel-usage-limited-info.png -------------------------------------------------------------------------------- /doc/kernel-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/kernel-usage.png -------------------------------------------------------------------------------- /doc/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/settings.png -------------------------------------------------------------------------------- /doc/statusbar-cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/statusbar-cpu.png -------------------------------------------------------------------------------- /doc/statusbar-warn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/statusbar-warn.png -------------------------------------------------------------------------------- /doc/statusbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/statusbar.png -------------------------------------------------------------------------------- /doc/statusbar_disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/statusbar_disk.png -------------------------------------------------------------------------------- /doc/topbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyter-server/jupyter-resource-usage/97f87085567878bd9432d7bca3ee60c7ebdb5374/doc/topbar.gif -------------------------------------------------------------------------------- /install.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageManager": "python", 3 | "packageName": "jupyter-resource-usage", 4 | "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyter-resource-usage" 5 | } 6 | -------------------------------------------------------------------------------- /jupyter-config/jupyter_notebook_config.d/jupyter_resource_usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "NotebookApp": { 3 | "nbserver_extensions": { 4 | "jupyter_resource_usage": true 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jupyter-config/jupyter_server_config.d/jupyter_resource_usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "ServerApp": { 3 | "jpserver_extensions": { 4 | "jupyter_resource_usage": true 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jupyter-config/nbconfig/notebook.d/jupyter_resource_usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "load_extensions": { 3 | "jupyter_resource_usage/main": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /jupyter_resource_usage/__init__.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from ._version import __version__ 4 | from .server_extension import load_jupyter_server_extension 5 | 6 | 7 | def _jupyter_labextension_paths(): 8 | return [{"src": "labextension", "dest": "@jupyter-server/resource-usage"}] 9 | 10 | 11 | def _jupyter_server_extension_points(): 12 | """ 13 | Set up the server extension for collecting metrics 14 | """ 15 | return [{"module": "jupyter_resource_usage"}] 16 | 17 | 18 | def _jupyter_nbextension_paths(): 19 | """ 20 | Set up the notebook extension for displaying metrics 21 | """ 22 | return [ 23 | { 24 | "section": "notebook", 25 | "dest": "jupyter_resource_usage", 26 | "src": "static", 27 | "require": "jupyter_resource_usage/main", 28 | } 29 | ] 30 | 31 | 32 | # For backward compatibility 33 | _load_jupyter_server_extension = load_jupyter_server_extension 34 | _jupyter_server_extension_paths = _jupyter_server_extension_points 35 | -------------------------------------------------------------------------------- /jupyter_resource_usage/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.1.1" 2 | -------------------------------------------------------------------------------- /jupyter_resource_usage/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | from concurrent.futures import ThreadPoolExecutor 3 | from inspect import isawaitable 4 | 5 | import psutil 6 | import zmq.asyncio 7 | from jupyter_client.jsonutil import date_default 8 | from jupyter_server.base.handlers import APIHandler 9 | from packaging import version 10 | from tornado import web 11 | from tornado.concurrent import run_on_executor 12 | 13 | 14 | try: 15 | import ipykernel 16 | 17 | IPYKERNEL_VERSION = ipykernel.__version__ 18 | USAGE_IS_SUPPORTED = version.parse("6.9.0") <= version.parse(IPYKERNEL_VERSION) 19 | except ImportError: 20 | USAGE_IS_SUPPORTED = False 21 | IPYKERNEL_VERSION = None 22 | 23 | 24 | class ApiHandler(APIHandler): 25 | executor = ThreadPoolExecutor(max_workers=5) 26 | 27 | @web.authenticated 28 | async def get(self): 29 | """ 30 | Calculate and return current resource usage metrics 31 | """ 32 | config = self.settings["jupyter_resource_usage_display_config"] 33 | 34 | cur_process = psutil.Process() 35 | all_processes = [cur_process] + cur_process.children(recursive=True) 36 | 37 | # Get memory information 38 | rss = 0 39 | pss = None 40 | for p in all_processes: 41 | try: 42 | info = p.memory_full_info() 43 | if hasattr(info, "pss"): 44 | pss = (pss or 0) + info.pss 45 | rss += info.rss 46 | except (psutil.NoSuchProcess, psutil.AccessDenied) as e: 47 | pass 48 | 49 | if callable(config.mem_limit): 50 | mem_limit = config.mem_limit(rss=rss, pss=pss) 51 | else: # mem_limit is an Int 52 | mem_limit = config.mem_limit 53 | 54 | limits = {"memory": {"rss": mem_limit, "pss": mem_limit}} 55 | if config.mem_limit and config.mem_warning_threshold != 0: 56 | limits["memory"]["warn"] = (mem_limit - rss) < ( 57 | mem_limit * config.mem_warning_threshold 58 | ) 59 | 60 | metrics = {"rss": rss, "limits": limits} 61 | if pss is not None: 62 | metrics["pss"] = pss 63 | 64 | # Optionally get CPU information 65 | if config.track_cpu_percent: 66 | cpu_count = psutil.cpu_count() 67 | cpu_percent = await self._get_cpu_percent(all_processes) 68 | 69 | if config.cpu_limit != 0: 70 | limits["cpu"] = {"cpu": config.cpu_limit} 71 | if config.cpu_warning_threshold != 0: 72 | limits["cpu"]["warn"] = (config.cpu_limit - cpu_percent) < ( 73 | config.cpu_limit * config.cpu_warning_threshold 74 | ) 75 | 76 | metrics.update(cpu_percent=cpu_percent, cpu_count=cpu_count) 77 | 78 | # Optionally get Disk information 79 | if config.track_disk_usage: 80 | try: 81 | disk_info = psutil.disk_usage(config.disk_path) 82 | except Exception: 83 | pass 84 | else: 85 | metrics.update(disk_used=disk_info.used, disk_total=disk_info.total) 86 | limits["disk"] = {"disk": disk_info.total} 87 | if config.disk_warning_threshold != 0: 88 | limits["disk"]["warn"] = (disk_info.total - disk_info.used) < ( 89 | disk_info.total * config.disk_warning_threshold 90 | ) 91 | 92 | self.write(json.dumps(metrics)) 93 | 94 | @run_on_executor 95 | def _get_cpu_percent(self, all_processes): 96 | def get_cpu_percent(p): 97 | try: 98 | return p.cpu_percent(interval=0.05) 99 | # Avoid littering logs with stack traces complaining 100 | # about dead processes having no CPU usage 101 | except: 102 | return 0 103 | 104 | return sum([get_cpu_percent(p) for p in all_processes]) 105 | 106 | 107 | class KernelUsageHandler(APIHandler): 108 | @web.authenticated 109 | async def get(self, matched_part=None, *args, **kwargs): 110 | if not USAGE_IS_SUPPORTED: 111 | self.write( 112 | json.dumps( 113 | { 114 | "content": { 115 | "reason": "not_supported", 116 | "kernel_version": IPYKERNEL_VERSION, 117 | } 118 | } 119 | ) 120 | ) 121 | return 122 | 123 | config = self.settings["jupyter_resource_usage_display_config"] 124 | 125 | kernel_id = matched_part 126 | km = self.kernel_manager 127 | lkm = km.pinned_superclass.get_kernel(km, kernel_id) 128 | session = lkm.session 129 | client = lkm.client() 130 | 131 | control_channel = client.control_channel 132 | usage_request = session.msg("usage_request", {}) 133 | control_channel.send(usage_request) 134 | poller = zmq.asyncio.Poller() 135 | control_socket = control_channel.socket 136 | poller.register(control_socket, zmq.POLLIN) 137 | timeout_ms = 10_000 138 | events = dict(await poller.poll(timeout_ms)) 139 | if control_socket not in events: 140 | out = json.dumps( 141 | { 142 | "content": {"reason": "timeout", "timeout_ms": timeout_ms}, 143 | "kernel_id": kernel_id, 144 | } 145 | ) 146 | 147 | else: 148 | res = client.control_channel.get_msg(timeout=0) 149 | if isawaitable(res): 150 | # control_channel.get_msg may return a Future, 151 | # depending on configured KernelManager class 152 | res = await res 153 | if res: 154 | res["kernel_id"] = kernel_id 155 | res["content"].update({"host_usage_flag": config.show_host_usage}) 156 | out = json.dumps(res, default=date_default) 157 | client.stop_channels() 158 | self.write(out) 159 | -------------------------------------------------------------------------------- /jupyter_resource_usage/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from traitlets import Bool 4 | from traitlets import default 5 | from traitlets import Dict 6 | from traitlets import Float 7 | from traitlets import Int 8 | from traitlets import List 9 | from traitlets import TraitType 10 | from traitlets import Unicode 11 | from traitlets import Union 12 | from traitlets.config import Configurable 13 | 14 | try: 15 | # Traitlets >= 4.3.3 16 | from traitlets import Callable 17 | except ImportError: 18 | from .utils import Callable 19 | 20 | 21 | class PSUtilMetric(TraitType): 22 | """A trait describing the format to specify a metric from the psutil package""" 23 | 24 | info_text = "A dictionary specifying the function/method name, any keyword arguments, and if a named tuple is returned, which attribute of the named tuple to select" 25 | 26 | def validate(self, obj, value): 27 | if isinstance(value, dict): 28 | keys = list(value.keys()) 29 | if "name" in keys: 30 | keys.remove("name") 31 | if all(key in ["args", "kwargs", "attribute"] for key in keys): 32 | return value 33 | self.error(obj, value) 34 | 35 | 36 | class ResourceUseDisplay(Configurable): 37 | """ 38 | Holds server-side configuration for jupyter-resource-usage 39 | """ 40 | 41 | # Needs to be defined early, so the metrics can use it. 42 | disk_path = Union( 43 | trait_types=[Unicode(), Callable()], 44 | default_value="/home/jovyan", 45 | help=""" 46 | A path in the partition to be reported on. 47 | """, 48 | ).tag(config=True) 49 | 50 | process_memory_metrics = List( 51 | trait=PSUtilMetric(), 52 | default_value=[{"name": "memory_info", "attribute": "rss"}], 53 | ) 54 | 55 | system_memory_metrics = List( 56 | trait=PSUtilMetric(), 57 | default_value=[{"name": "virtual_memory", "attribute": "total"}], 58 | ) 59 | 60 | process_cpu_metrics = List( 61 | trait=PSUtilMetric(), 62 | default_value=[{"name": "cpu_percent", "kwargs": {"interval": 0.05}}], 63 | ) 64 | 65 | system_cpu_metrics = List( 66 | trait=PSUtilMetric(), default_value=[{"name": "cpu_count"}] 67 | ) 68 | 69 | process_disk_metrics = List( 70 | trait=PSUtilMetric(), 71 | default_value=[], 72 | ) 73 | 74 | system_disk_metrics = List( 75 | trait=PSUtilMetric(), 76 | default_value=[ 77 | {"name": "disk_usage", "args": [disk_path], "attribute": "total"}, 78 | {"name": "disk_usage", "args": [disk_path], "attribute": "used"}, 79 | ], 80 | ) 81 | 82 | mem_warning_threshold = Float( 83 | default_value=0.1, 84 | help=""" 85 | Warn user with flashing lights when memory usage is within this fraction 86 | memory limit. 87 | 88 | For example, if memory limit is 128MB, `mem_warning_threshold` is 0.1, 89 | we will start warning the user when they use (128 - (128 * 0.1)) MB. 90 | 91 | Set to 0 to disable warning. 92 | """, 93 | ).tag(config=True) 94 | 95 | mem_limit = Union( 96 | trait_types=[Int(), Callable()], 97 | help=""" 98 | Memory limit to display to the user, in bytes. 99 | Can also be a function which calculates the memory limit. 100 | 101 | Note that this does not actually limit the user's memory usage! 102 | 103 | Defaults to reading from the `MEM_LIMIT` environment variable. If 104 | set to 0, the max memory available is displayed. 105 | """, 106 | ).tag(config=True) 107 | 108 | @default("mem_limit") 109 | def _mem_limit_default(self): 110 | return int(os.environ.get("MEM_LIMIT", 0)) 111 | 112 | track_cpu_percent = Bool( 113 | default_value=False, 114 | help=""" 115 | Set to True in order to enable reporting of CPU usage statistics. 116 | """, 117 | ).tag(config=True) 118 | 119 | cpu_warning_threshold = Float( 120 | default_value=0.1, 121 | help=""" 122 | Warn user with flashing lights when CPU usage is within this fraction 123 | CPU usage limit. 124 | 125 | For example, if CPU limit is 150%, `cpu_warning_threshold` is 0.1, 126 | we will start warning the user when they use (150 - (150 * 0.1)) %. 127 | 128 | Set to 0 to disable warning. 129 | """, 130 | ).tag(config=True) 131 | 132 | cpu_limit = Union( 133 | trait_types=[Float(), Callable()], 134 | default_value=0, 135 | help=""" 136 | CPU usage limit to display to the user. 137 | 138 | Note that this does not actually limit the user's CPU usage! 139 | 140 | Defaults to reading from the `CPU_LIMIT` environment variable. If 141 | set to 0, the total CPU count available is displayed. 142 | """, 143 | ).tag(config=True) 144 | 145 | @default("cpu_limit") 146 | def _cpu_limit_default(self): 147 | return float(os.environ.get("CPU_LIMIT", 0)) 148 | 149 | track_disk_usage = Bool( 150 | default_value=False, 151 | help=""" 152 | Set to True in order to enable reporting of disk usage statistics. 153 | """, 154 | ).tag(config=True) 155 | 156 | @default("disk_path") 157 | def _disk_path_default(self): 158 | return str(os.environ.get("HOME", "/home/jovyan")) 159 | 160 | disk_warning_threshold = Float( 161 | default_value=0.1, 162 | help=""" 163 | Warn user with flashing lights when disk usage is within this fraction 164 | total space. 165 | 166 | For example, if total size is 10G, `disk_warning_threshold` is 0.1, 167 | we will start warning the user when they use (10 - (10 * 0.1)) G. 168 | 169 | Set to 0 to disable warning. 170 | """, 171 | ).tag(config=True) 172 | 173 | enable_prometheus_metrics = Bool( 174 | default_value=True, 175 | help=""" 176 | Set to False in order to disable reporting of Prometheus style metrics. 177 | """, 178 | ).tag(config=True) 179 | 180 | show_host_usage = Bool( 181 | default_value=True, 182 | help=""" 183 | Set to True in order to show host cpu and host virtual memory info. 184 | """, 185 | ).tag(config=True) 186 | -------------------------------------------------------------------------------- /jupyter_resource_usage/metrics.py: -------------------------------------------------------------------------------- 1 | try: 2 | import psutil 3 | except ImportError: 4 | psutil = None 5 | 6 | from jupyter_server.serverapp import ServerApp 7 | 8 | 9 | class PSUtilMetricsLoader: 10 | def __init__(self, server_app: ServerApp): 11 | self.config = server_app.web_app.settings[ 12 | "jupyter_resource_usage_display_config" 13 | ] 14 | self.server_app = server_app 15 | 16 | def get_process_metric_value(self, process, name, args, kwargs, attribute=None): 17 | try: 18 | # psutil.Process methods will either return... 19 | metric_value = getattr(process, name)(*args, **kwargs) 20 | if attribute is not None: # ... a named tuple 21 | return getattr(metric_value, attribute) 22 | else: # ... or a number 23 | return metric_value 24 | # Avoid littering logs with stack traces 25 | # complaining about dead processes 26 | except BaseException: 27 | return 0 28 | 29 | def process_metric(self, name, args=[], kwargs={}, attribute=None): 30 | if psutil is None: 31 | return None 32 | else: 33 | current_process = psutil.Process() 34 | all_processes = [current_process] + current_process.children(recursive=True) 35 | 36 | process_metric_value = lambda process: self.get_process_metric_value( 37 | process, name, args, kwargs, attribute 38 | ) 39 | 40 | return sum([process_metric_value(process) for process in all_processes]) 41 | 42 | def system_metric(self, name, args=[], kwargs={}, attribute=None): 43 | if psutil is None: 44 | return None 45 | else: 46 | # psutil functions will either raise an error, or return... 47 | try: 48 | metric_value = getattr(psutil, name)(*args, **kwargs) 49 | except: 50 | return None 51 | if attribute is not None: # ... a named tuple 52 | return getattr(metric_value, attribute) 53 | else: # ... or a number 54 | return metric_value 55 | 56 | def get_metric_values(self, metrics, metric_type): 57 | metric_types = {"process": self.process_metric, "system": self.system_metric} 58 | metric_value = metric_types[metric_type] # Switch statement 59 | 60 | metric_values = {} 61 | for metric in metrics: 62 | name = metric["name"] 63 | if metric.get("attribute", False): 64 | name += "_" + metric.get("attribute") 65 | metric_values.update({name: metric_value(**metric)}) 66 | return metric_values 67 | 68 | def metrics(self, process_metrics, system_metrics): 69 | metric_values = {} 70 | if process_metrics: 71 | metric_values.update(self.get_metric_values(process_metrics, "process")) 72 | if system_metrics: 73 | metric_values.update(self.get_metric_values(system_metrics, "system")) 74 | 75 | if any(value is None for value in metric_values.values()): 76 | return None 77 | 78 | return metric_values 79 | 80 | def memory_metrics(self): 81 | return self.metrics( 82 | self.config.process_memory_metrics, self.config.system_memory_metrics 83 | ) 84 | 85 | def cpu_metrics(self): 86 | return self.metrics( 87 | self.config.process_cpu_metrics, self.config.system_cpu_metrics 88 | ) 89 | 90 | def disk_metrics(self): 91 | return self.metrics( 92 | self.config.process_disk_metrics, self.config.system_disk_metrics 93 | ) 94 | -------------------------------------------------------------------------------- /jupyter_resource_usage/prometheus.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from prometheus_client import Gauge 4 | 5 | from jupyter_resource_usage.metrics import PSUtilMetricsLoader 6 | 7 | try: 8 | # Traitlets >= 4.3.3 9 | from traitlets import Callable 10 | except ImportError: 11 | from .utils import Callable 12 | 13 | 14 | class PrometheusHandler(Callable): 15 | def __init__(self, metricsloader: PSUtilMetricsLoader): 16 | super().__init__() 17 | self.metricsloader = metricsloader 18 | self.config = metricsloader.config 19 | self.session_manager = metricsloader.server_app.session_manager 20 | 21 | gauge_names = [ 22 | "total_memory", 23 | "max_memory", 24 | "total_cpu", 25 | "max_cpu", 26 | "max_disk", 27 | "current_disk", 28 | ] 29 | for name in gauge_names: 30 | phrase = name + "_usage" 31 | gauge = Gauge(phrase, "counter for " + phrase.replace("_", " "), []) 32 | setattr(self, phrase.upper(), gauge) 33 | 34 | async def __call__(self, *args, **kwargs): 35 | memory_metric_values = self.metricsloader.memory_metrics() 36 | if memory_metric_values is not None: 37 | self.TOTAL_MEMORY_USAGE.set(memory_metric_values["memory_info_rss"]) 38 | self.MAX_MEMORY_USAGE.set(self.apply_memory_limit(memory_metric_values)) 39 | if self.config.track_cpu_percent: 40 | cpu_metric_values = self.metricsloader.cpu_metrics() 41 | if cpu_metric_values is not None: 42 | self.TOTAL_CPU_USAGE.set(cpu_metric_values["cpu_percent"]) 43 | self.MAX_CPU_USAGE.set(self.apply_cpu_limit(cpu_metric_values)) 44 | if self.config.track_disk_usage: 45 | disk_metric_values = self.metricsloader.disk_metrics() 46 | if disk_metric_values is not None: 47 | self.CURRENT_DISK_USAGE.set(disk_metric_values["disk_usage_used"]) 48 | self.MAX_DISK_USAGE.set(disk_metric_values["disk_usage_total"]) 49 | 50 | def apply_memory_limit(self, memory_metric_values) -> Optional[int]: 51 | if memory_metric_values is None: 52 | return None 53 | else: 54 | if callable(self.config.mem_limit): 55 | return self.config.mem_limit( 56 | rss=memory_metric_values["memory_info_rss"] 57 | ) 58 | elif self.config.mem_limit > 0: # mem_limit is an Int 59 | return self.config.mem_limit 60 | else: 61 | return memory_metric_values["virtual_memory_total"] 62 | 63 | def apply_cpu_limit(self, cpu_metric_values) -> Optional[float]: 64 | if cpu_metric_values is None: 65 | return None 66 | else: 67 | if callable(self.config.cpu_limit): 68 | return self.config.cpu_limit( 69 | cpu_percent=cpu_metric_values["cpu_percent"] 70 | ) 71 | elif self.config.cpu_limit > 0.0: # cpu_limit is a Float 72 | return self.config.cpu_limit 73 | else: 74 | return 100.0 * cpu_metric_values["cpu_count"] 75 | -------------------------------------------------------------------------------- /jupyter_resource_usage/server_extension.py: -------------------------------------------------------------------------------- 1 | from jupyter_server.utils import url_path_join 2 | from tornado import ioloop 3 | 4 | from jupyter_resource_usage.api import ApiHandler 5 | from jupyter_resource_usage.api import KernelUsageHandler 6 | from jupyter_resource_usage.config import ResourceUseDisplay 7 | from jupyter_resource_usage.metrics import PSUtilMetricsLoader 8 | from jupyter_resource_usage.prometheus import PrometheusHandler 9 | 10 | 11 | def load_jupyter_server_extension(server_app): 12 | """ 13 | Called during notebook start 14 | """ 15 | resuseconfig = ResourceUseDisplay(parent=server_app) 16 | server_app.web_app.settings["jupyter_resource_usage_display_config"] = resuseconfig 17 | base_url = server_app.web_app.settings["base_url"] 18 | 19 | server_app.web_app.add_handlers( 20 | ".*", [(url_path_join(base_url, "/api/metrics/v1"), ApiHandler)] 21 | ) 22 | server_app.web_app.add_handlers( 23 | ".*$", 24 | [ 25 | ( 26 | url_path_join( 27 | base_url, "/api/metrics/v1/kernel_usage", r"get_usage/(.+)$" 28 | ), 29 | KernelUsageHandler, 30 | ) 31 | ], 32 | ) 33 | 34 | if resuseconfig.enable_prometheus_metrics: 35 | callback = ioloop.PeriodicCallback( 36 | PrometheusHandler(PSUtilMetricsLoader(server_app)), 1000 37 | ) 38 | callback.start() 39 | else: 40 | server_app.log.info( 41 | "Prometheus metrics reporting disabled in jupyter_resource_usage." 42 | ) 43 | -------------------------------------------------------------------------------- /jupyter_resource_usage/static/main.js: -------------------------------------------------------------------------------- 1 | define([ // eslint-disable-line no-undef 2 | 'jquery', 3 | 'base/js/utils' 4 | ], ($, utils) => { 5 | function setupDOM() { 6 | $('#maintoolbar-container').append( 7 | $('