diff --git a/.github/workflows/actions/setup/action.yml b/.github/workflows/actions/setup/action.yml new file mode 100755 index 0000000..9373e0f --- /dev/null +++ b/.github/workflows/actions/setup/action.yml @@ -0,0 +1,30 @@ +name: Setup Environment +description: Performs setup of Python and its dependencies +inputs: + python-version: + description: 'Python version to run' + required: true + +runs: + using: 'composite' + steps: + - name: Set up Python ${{ inputs.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ inputs.python-version }} + cache: 'pip' + + - name: Install Unix dependencies + shell: sh + run: | + sudo apt-get -qq update + + - name: Upgrade pip and build dependencies + shell: sh + run: | + python -m pip install --upgrade pip setuptools + + - name: Install Tox + shell: sh + run: | + pip install tox diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100755 index 0000000..cc9106b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Release + +on: + pull_request: + types: + - closed + branches: + - devel + +jobs: + release: + if: ${{ github.event.pull_request.merged == true && contains(github.head_ref, 'release') }} + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + steps: + - name: Checkout latest version + uses: actions/checkout@v3 + with: + ref: devel + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Install logki (to assure it is correctly installed) and try obtaining the version + run: | + make install + logki --version + + - name: Set version + id: manual-tagger + run: echo "NEW_TAG=$(logki --version | cut -d' ' -f2)" >> "$GITHUB_OUTPUT" + + - name: Tag the new version + uses: rickstaa/action-create-tag@v1.7.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ steps.manual-tagger.outputs.NEW_TAG }} + + build-and-deploy-to-pypi: + needs: release + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - name: Checkout latest version + uses: actions/checkout@v3 + with: + ref: devel + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Ensure that dependencies are installed + run: | + # Install and upgrade pip + python3 -m pip install --upgrade pip + # Install dependencies for build and deploy + python3 -m pip install build wheel twine + + - name: Build python release distribution package + run: | + make release + + - name: Upload to TestPypi + run: | + python3 -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.TESTPYPI_SECRET_TOKEN }} + TWINE_REPOSITORY: testpypi + + - name: Upload to Pypi + run: | + python3 -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_SECRET_TOKEN }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml new file mode 100755 index 0000000..9f110b1 --- /dev/null +++ b/.github/workflows/ubuntu.yml @@ -0,0 +1,111 @@ +name: Ubuntu (build-&-test) + +on: + push: + branches: + - devel + pull_request: + branches: + - devel + +jobs: + # Tests classic build using Tox for selected Python versions + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Execute tests for Python ${{ matrix.python-version }} using Tox + run: tox -e py + + - name: Generate docs for Python ${{ matrix.python-version }} using Tox + run: | + tox -e docs + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + flags: coverage-${{ matrix.python-version }} + verbose: true + + # Tests that logki is buildable from distribution packages (this is precursor for pypi install). + # We limit the test to version 3.11 in order to have less clutter in Actions + build-from-dist: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Create tarball or wheel + run: | + pip3 install -q build + make release + + - name: Install from dist (wheel) + run: | + pip3 install dist/*.whl + + - name: Install from dist (tar.gz) + run: | + pip3 install dist/*.tar.gz + + - name: Try running logki and getting help + run: | + logki --version + + # Tests correctes of typing for all versions + typing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Check type correctness for Python ${{ matrix.python-version }} using Tox + run: | + tox -e typing + + # Test linting only for the latest version of python + linting: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Check lint correctness for Python ${{ matrix.python-version }} using Tox + run: | + tox -e lint || true + diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100755 index 0000000..fabbb7b --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,12 @@ + +=============== +Main Developers +=============== + +The following lists the authors (active ones are bold) that contributed to upstream (or to some fork) of logki: + + + * **Tomas Fiedor**: |github| `tfiedor `_ |email| `TomasFiedor@gmail.com `_ (original author) + +.. |github| image:: ./figs/icon-github.svg +.. |email| image:: ./figs/icon-email.svg diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100755 index 0000000..787dd42 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,7 @@ +Changelog +========= + +1.0 (2024-04-19) +------------------- + + - Main version of logki \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100755 index 0000000..ddcec33 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,36 @@ +Contributing +============ + +In case you run into some unexpected behaviour, error or anything suspicious, either contact us +directly through mail or [create a new Issue](https://github.com/Perfexionists/logki/issues/new). + +If you'd like to contribute, please first fork our repository and create a new dedicated feature branch starting from +the `develop` branch. Pull requests are warmly welcome! We will surely review the contribution (possibly request +some changes). However, please follow these guidelines: + + 1. **Document your code properly**---refer to + [sphinx documentation](http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain) + for the format compatible with our documentation. + + 2. **Test your code** within reasonable code coverage. The tests should be in the + directory and should achieve a suitable + amount of codecov coverage. + + 3. **Follow the project formatting**; we recommend using the [black](https://github.com/psf/black) formatter. + + 4. **Commit properly**: write meaningful commit messages; we recommend to write first short line as a short + description that can be included into the following template: "This commit will ___". + +Before considering a merge of pull requests we want the feature branch to fulfill the following: + + 1. The branch must be compilable (i.e. Github Action checks are passing); + 2. The tests cover reasonable proportion of code (i.e. codecov checks are passing); + 3. The code has no issues checked by codacy; + 4. At least one of the major maintainers has reviewed the code. + +If you think your extension could help others, please [send us +PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case it is, +indeed, suitable for wider audience and maintainable, we will include it in our +[upstream](https://github.com/Perfexionists/logki). + +*But, please be understanding; we cannot fix and merge everything.* diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..86904fa --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +help: + @echo "Logki - Log Analysis Kit" + @echo "" + @echo "For best developer experience, make sure to use a virtual environment." + @echo "For more information about how to contribute, see the CONTRIBUTING file." + @echo "" + @echo "Main commands:" + @echo " dev Install all dependencies and set up an editable environment" + @echo " install Install the project" + @echo " lint Run linters (black, pylint)" + @echo " check Run static type checker (mypy)" + @echo " test Run tests with pytest" + @echo " release Generate sdist and wheel" + +.PHONY: help dev install check lint test release docs docs-release docs-all docs-html docs-dirhtml docs-latex + +# Base build requirements are not installed automatically. +# Inspired by https://meson-python.readthedocs.io/en/latest/how-to-guides/editable-installs.html +dev: + $(info [INFO] Make sure you're using a virtual environment for development) + python3 -m pip install --no-build-isolation --config-settings=editable-verbose=true --config-settings=setup-args=-Dbuildtype=debug --editable .[test,typing,lint,docs] + +install: + pip3 install . + +check: + python3 -m mypy ./logki/ + +lint: + python3 -m black -q ./logki/ + python3 -m pylint --jobs 0 ./logki/ || true + +test: + python3 -m pytest --durations=10 --cov=./ --cov-report term-missing:skip-covered ./tests/ + +# In the CI environemnt we want to see all the tests and want coverage report to be in XML +# because the results are being uploaded to Codecov. +test-ci: + python3 -m pytest --cov=./ --cov-report xml --cov-report term-missing:skip-covered ./tests/ + +release: + python3 -m build \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 1c80587..66fc197 --- a/README.md +++ b/README.md @@ -1,2 +1,102 @@ -# logki -Logki is a prompt application for analysis of logs mainly resulting from performance profilers. +# logki: Lightweight Performance Version System + +[![build status](https://github.com/Perfexionists/logki/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/Perfexionists/logki/actions) +[![codecov](https://codecov.io/gh/Perfexionists/logki/graph/badge.svg?token=3x4Luodr84)](https://codecov.io/gh/Perfexionists/logki) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/a704486b4679442cb2a53173475f79ca)](https://app.codacy.com/gh/Perfexionists/logki/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) +[![GitHub tag](https://img.shields.io/github/tag/Perfexionists/logki.svg)](https://github.com/Perfexionists/logki) + + +

+ +

+ +Logki is a log analysis toolkit: a prompt application for on-the-fly analysis of big logs. + +## Installation + +Note that we are no longer maintaining support for Python 3.8, nor do we support Python 3.12 +(this is due to some of its dependencies). Logki may work, but we strongly advise to upgrade your +Python to one of the supported version between Python 3.9 and Python 3.11. + +You can install logki from pip as follows: + + pip3 instal logki + +Alternatively you can install logki from the source code as follows: + + git clone https://github.com/Perfexionists/logki.git + cd logki + make install + +These commands install logki to your system as a runnable python package. You can then run logki +safely from the command line using the `logki` command. + +It is advised to verify that logki is running correctly in your environment as follows: + + # You can run this only once: it will initialize the requirements necessary for testing + make init-test + # Runs all tests using pytest + make test + +or alternatively using Tox if you wish to test for more Python versions +(see the [developing section](#developing)). + +## Developing + +In order to commit changes to the logki, you have to install logki in development mode: + + git clone https://github.com/Perfexionists/logki.git + cd logki + make dev + +This method of installation allows you to make a changes to the code, which will be then reflected +by the installation. + +If you are interested in contributing to logki project, please refer to +[contributing](CONTRIBUTING) section. If you think your results could help others, please [send us +PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case it is +suitable for wider audience, we will include it in our [upstream](https://github.com/Perfexionists/logki). + +But, please be understanding, we cannot fix and merge everything immediately. + +## Getting Started + +Simply run the following command: + + logki [LOGFILE] + +Contributing +------------ + +If you'd like to contribute, please first fork our repository and create a dedicated feature branch. Pull requests are +warmly welcome. We will review the contribution (possibly request some changes). + +In case you run into some unexpected behaviour, error or anything suspicious, either contact us +directly through mail or [create a new Issue](https://github.com/Perfexionists/logki/issues/new). + +If you are interested in contributing to logki project, please first refer to +[contributing](Contributing.md) section. If you think your custom module could help others, please +[send us PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case +it is suitable for wider audience, we will include it in our +[upstream](https://github.com/Perfexionists/logki). + +But, please be understanding, we cannot fix and merge everything. + +Links +----- + +- GitHub repository : [https://github.com/Perfexionists/logki](https://github.com/Perfexionists/logki) +- Issue tracker: [https://github.com/Perfexionists/logki/issues](https://github.com/Perfexionists/logki/issues) + - In case of sensitive bugs like security vulnerabilities, please + contact [Tomas Fiedor](mailto:TomasFiedor@gmail.com) directly + instead of using issue tracker. We value your effort to improve the security and privacy of our project! + +Unrelated links: + +- Check out our research group focusing on program analysis, static and dynamic analysis, formal methods, verification + and many more: [VeriFIT](http://www.fit.vutbr.cz/research/groups/verifit/index.php.en) + +Licensing +--------- + +The code in this project is licensed under [GNU GPLv3 license](https://github.com/Perfexionists/logki/blob/devel/LICENSE). \ No newline at end of file diff --git a/examples/example.log b/examples/example.log new file mode 100755 index 0000000..57d4bf9 --- /dev/null +++ b/examples/example.log @@ -0,0 +1,222 @@ +449651305717147:(21845:21845)(kfree):call +449651305724100:(21845:21845)(kfree):return +449651305725579:(21845:21845)(kfree):call +449651305727153:(21845:21845)(__kmem_cache_free):call +449651305728525:(21845:21845)(__kmem_cache_free):return +449651305800008:(21845:21845)(kfree):return +449651305812030:(21845:21845)(kmem_cache_free):call +449651305821701:(21845:21845)(kmem_cache_free):return +449651305830381:(21845:21845)(syscall_exit_to_user_mode_prepare):call +449651305839140:(21845:21845)(syscall_exit_work):call +449651305849913:(21845:21845)(__audit_syscall_exit):call +449651305852432:(21845:21845)(__audit_syscall_exit):return +449651305854838:(21845:21845)(syscall_exit_work):return +449651305857253:(21845:21845)(syscall_exit_to_user_mode_prepare):return +449651305860482:(21845:21845)(exit_to_user_mode_prepare):call +449651305863155:(21845:21845)(_raw_spin_lock_irq):call +449651305865704:(21845:21845)(_raw_spin_lock_irq):return +449651305867916:(21845:21845)(_raw_spin_unlock_irq):call +449651305870599:(21845:21845)(_raw_spin_unlock_irq):return +449651305874335:(21845:21845)(__fput):call +449651305877772:(21845:21845)(__cond_resched):call +449651305879997:(21845:21845)(__cond_resched):return +449651305883346:(21845:21845)(mutex_lock):call +449651305884906:(21845:21845)(__cond_resched):call +449651305886964:(21845:21845)(__cond_resched):return +449651305889290:(21845:21845)(mutex_lock):return +449651305891884:(21845:21845)(_raw_spin_lock_irqsave):call +449651305893291:(21845:21845)(_raw_spin_lock_irqsave):return +449651305896600:(21845:21845)(_raw_spin_lock_irqsave):call +449651305897845:(21845:21845)(_raw_spin_lock_irqsave):return +449651305904870:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305907734:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305910259:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305915942:(21845:21845)(irq_enter_rcu):call +449651305921833:(21845:21845)(irqtime_account_irq):call +449651305925693:(21845:21845)(irqtime_account_irq):return +449651305929083:(21845:21845)(irq_enter_rcu):return +449651305936148:(21845:21845)(_raw_spin_lock_irqsave):call +449651305940816:(21845:21845)(_raw_spin_lock_irqsave):return +449651305947899:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305950353:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305952634:(21845:21845)(irq_exit_rcu):call +449651305955607:(21845:21845)(irqtime_account_irq):call +449651305958536:(21845:21845)(irqtime_account_irq):return +449651305960003:(21845:21845)(idle_cpu):call +449651305961408:(21845:21845)(idle_cpu):return +449651305962940:(21845:21845)(irq_exit_rcu):return +449651305964981:(21845:21845)(irq_enter_rcu):call +449651305966218:(21845:21845)(irqtime_account_irq):call +449651305967360:(21845:21845)(irqtime_account_irq):return +449651305968847:(21845:21845)(irq_enter_rcu):return +449651305970808:(21845:21845)(_raw_spin_lock_irqsave):call +449651305972420:(21845:21845)(_raw_spin_lock_irqsave):return +449651305974211:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305976131:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305978135:(21845:21845)(irq_exit_rcu):call +449651305979253:(21845:21845)(irqtime_account_irq):call +449651305981001:(21845:21845)(irqtime_account_irq):return +449651305982200:(21845:21845)(idle_cpu):call +449651305983705:(21845:21845)(idle_cpu):return +449651305984769:(21845:21845)(irq_exit_rcu):return +449651305986522:(21845:21845)(irq_enter_rcu):call +449651305988310:(21845:21845)(irqtime_account_irq):call +449651305990191:(21845:21845)(irqtime_account_irq):return +449651305991169:(21845:21845)(irq_enter_rcu):return +449651305992998:(21845:21845)(_raw_spin_lock_irqsave):call +449651305994149:(21845:21845)(_raw_spin_lock_irqsave):return +449651305995996:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305997094:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305999290:(21845:21845)(irq_exit_rcu):call +449651306000856:(21845:21845)(irqtime_account_irq):call +449651306002263:(21845:21845)(irqtime_account_irq):return +449651306003488:(21845:21845)(idle_cpu):call +449651306004589:(21845:21845)(idle_cpu):return +449651306005970:(21845:21845)(irq_exit_rcu):return +449651306007730:(21845:21845)(irq_enter_rcu):call +449651306008978:(21845:21845)(irqtime_account_irq):call +449651306010408:(21845:21845)(irqtime_account_irq):return +449651306011786:(21845:21845)(irq_enter_rcu):return +449651306013923:(21845:21845)(_raw_spin_lock_irqsave):call +449651306015042:(21845:21845)(_raw_spin_lock_irqsave):return +449651306017104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306018366:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306020129:(21845:21845)(irq_exit_rcu):call +449651306021165:(21845:21845)(irqtime_account_irq):call +449651306022889:(21845:21845)(irqtime_account_irq):return +449651306024142:(21845:21845)(idle_cpu):call +449651306025704:(21845:21845)(idle_cpu):return +449651306026937:(21845:21845)(irq_exit_rcu):return +449651306028874:(21845:21845)(irq_enter_rcu):call +449651306030361:(21845:21845)(irqtime_account_irq):call +449651306032054:(21845:21845)(irqtime_account_irq):return +449651306033084:(21845:21845)(irq_enter_rcu):return +449651306035164:(21845:21845)(_raw_spin_lock_irqsave):call +449651306036445:(21845:21845)(_raw_spin_lock_irqsave):return +449651306038223:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306039225:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306040914:(21845:21845)(irq_exit_rcu):call +449651306042387:(21845:21845)(irqtime_account_irq):call +449651306043823:(21845:21845)(irqtime_account_irq):return +449651306045094:(21845:21845)(idle_cpu):call +449651306046799:(21845:21845)(idle_cpu):return +449651306048282:(21845:21845)(irq_exit_rcu):return +449651306049905:(21845:21845)(irq_enter_rcu):call +449651306051063:(21845:21845)(irqtime_account_irq):call +449651306052677:(21845:21845)(irqtime_account_irq):return +449651306054156:(21845:21845)(irq_enter_rcu):return +449651306056001:(21845:21845)(_raw_spin_lock_irqsave):call +449651306057348:(21845:21845)(_raw_spin_lock_irqsave):return +449651306058914:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306060465:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306061750:(21845:21845)(irq_exit_rcu):call +449651306063251:(21845:21845)(irqtime_account_irq):call +449651306064998:(21845:21845)(irqtime_account_irq):return +449651306066683:(21845:21845)(idle_cpu):call +449651306067866:(21845:21845)(idle_cpu):return +449651306068994:(21845:21845)(irq_exit_rcu):return +449651306070886:(21845:21845)(irq_enter_rcu):call +449651306072286:(21845:21845)(irqtime_account_irq):call +449651306073883:(21845:21845)(irqtime_account_irq):return +449651306075087:(21845:21845)(irq_enter_rcu):return +449651306077129:(21845:21845)(_raw_spin_lock_irqsave):call +449651306078428:(21845:21845)(_raw_spin_lock_irqsave):return +449651306080104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306081289:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306082424:(21845:21845)(irq_exit_rcu):call +449651306084461:(21845:21845)(irqtime_account_irq):call +449651306085655:(21845:21845)(irqtime_account_irq):return +449651306087347:(21845:21845)(idle_cpu):call +449651306088245:(21845:21845)(idle_cpu):return +449651306089812:(21845:21845)(irq_exit_rcu):return +449651306091789:(21845:21845)(irq_enter_rcu):call +449651306093231:(21845:21845)(irqtime_account_irq):call +449651306094161:(21845:21845)(irqtime_account_irq):return +449651306095499:(21845:21845)(irq_enter_rcu):return +449651306097027:(21845:21845)(_raw_spin_lock_irqsave):call +449651306098434:(21845:21845)(_raw_spin_lock_irqsave):return +449651306100032:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306101322:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306103370:(21845:21845)(irq_exit_rcu):call +449651306105076:(21845:21845)(irqtime_account_irq):call +449651306106109:(21845:21845)(irqtime_account_irq):return +449651306107586:(21845:21845)(idle_cpu):call +449651306108988:(21845:21845)(idle_cpu):return +449651306110299:(21845:21845)(irq_exit_rcu):return +449651306112028:(21845:21845)(irq_enter_rcu):call +449651306113911:(21845:21845)(irqtime_account_irq):call +449651306115148:(21845:21845)(irqtime_account_irq):return +449651306116955:(21845:21845)(irq_enter_rcu):return +449651306118563:(21845:21845)(_raw_spin_lock_irqsave):call +449651306120193:(21845:21845)(_raw_spin_lock_irqsave):return +449651306121698:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306123240:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306124573:(21845:21845)(irq_exit_rcu):call +449651306126425:(21845:21845)(irqtime_account_irq):call +449651306128107:(21845:21845)(irqtime_account_irq):return +449651306129739:(21845:21845)(idle_cpu):call +449651306131113:(21845:21845)(idle_cpu):return +449651306132204:(21845:21845)(irq_exit_rcu):return +449651306134263:(21845:21845)(irq_enter_rcu):call +449651306135755:(21845:21845)(irqtime_account_irq):call +449651306137490:(21845:21845)(irqtime_account_irq):return +449651306138257:(21845:21845)(irq_enter_rcu):return +449651306139967:(21845:21845)(_raw_spin_lock_irqsave):call +449651306141326:(21845:21845)(_raw_spin_lock_irqsave):return +449651306142941:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306143993:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306146020:(21845:21845)(irq_exit_rcu):call +449651306147271:(21845:21845)(irqtime_account_irq):call +449651306149021:(21845:21845)(irqtime_account_irq):return +449651306150343:(21845:21845)(idle_cpu):call +449651306151936:(21845:21845)(idle_cpu):return +449651306153351:(21845:21845)(irq_exit_rcu):return +449651306155400:(21845:21845)(irq_enter_rcu):call +449651306156749:(21845:21845)(irqtime_account_irq):call +449651306158440:(21845:21845)(irqtime_account_irq):return +449651306159673:(21845:21845)(irq_enter_rcu):return +449651306160914:(21845:21845)(_raw_spin_lock_irqsave):call +449651306161783:(21845:21845)(_raw_spin_lock_irqsave):return +449651306163150:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306164098:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306165525:(21845:21845)(irq_exit_rcu):call +449651306166404:(21845:21845)(irqtime_account_irq):call +449651306167628:(21845:21845)(irqtime_account_irq):return +449651306169374:(21845:21845)(idle_cpu):call +449651306170457:(21845:21845)(idle_cpu):return +449651306171490:(21845:21845)(irq_exit_rcu):return +449651306172920:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306174229:(21845:21845)(_raw_spin_lock_irqsave):call +449651306175561:(21845:21845)(_raw_spin_lock_irqsave):return +449651306176842:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306177852:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306179116:(21845:21845)(mutex_unlock):call +449651306180884:(21845:21845)(mutex_unlock):return +449651306184624:(21845:21845)(_raw_spin_lock):call +449651306186282:(21845:21845)(_raw_spin_lock):return +449651306188480:(21845:21845)(_raw_spin_unlock):call +449651306189664:(21845:21845)(_raw_spin_unlock):return +449651306192308:(21845:21845)(dput):call +449651306194809:(21845:21845)(__cond_resched):call +449651306196639:(21845:21845)(__cond_resched):return +449651306198886:(21845:21845)(dput):return +449651306201957:(21845:21845)(mntput):call +449651306203024:(21845:21845)(mntput):return +449651306204139:(21845:21845)(kmem_cache_free):call +449651306205971:(21845:21845)(__slab_free):call +449651306208669:(21845:21845)(__slab_free):return +449651306210733:(21845:21845)(kmem_cache_free):return +449651306212495:(21845:21845)(__call_rcu_common.constprop.0):call +449651306214769:(21845:21845)(rcu_nocb_try_bypass):call +449651306217920:(21845:21845)(rcu_segcblist_pend_cbs):call +449651306219060:(21845:21845)(rcu_segcblist_pend_cbs):return +449651306220460:(21845:21845)(rcu_nocb_try_bypass):return +449651306224060:(21845:21845)(rcu_segcblist_enqueue):call +449651306226501:(21845:21845)(rcu_segcblist_enqueue):return +449651306228010:(21845:21845)(__call_rcu_common.constprop.0):return +449651306229147:(21845:21845)(__fput):return +449651306232040:(21845:21845)(__cond_resched):call +449651306235163:(21845:21845)(__cond_resched):return +449651306238018:(21845:21845)(mem_cgroup_handle_over_high):call +449651306240262:(21845:21845)(mem_cgroup_handle_over_high):return +449651306242616:(21845:21845)(exit_to_user_mode_prepare):return diff --git a/figs/logo.jpg b/figs/logo.jpg new file mode 100755 index 0000000..b45ddea Binary files /dev/null and b/figs/logo.jpg differ diff --git a/logki/__init__.py b/logki/__init__.py new file mode 100755 index 0000000..cf1690e --- /dev/null +++ b/logki/__init__.py @@ -0,0 +1,6 @@ +"""logki is a log analysis kit""" +from __future__ import annotations + +import importlib.metadata + +__version__ = importlib.metadata.version("logki") \ No newline at end of file diff --git a/logki/app.py b/logki/app.py new file mode 100755 index 0000000..3279a39 --- /dev/null +++ b/logki/app.py @@ -0,0 +1,425 @@ +"""logki is prompt script for going through the logs, for example of perun ktrace """ +from __future__ import annotations + +# Standard Imports +from typing import Optional, TextIO, Any +from dataclasses import dataclass +import io +import sys + +# Third-Party Imports +import tabulate +from prompt_toolkit import Application +from prompt_toolkit.key_binding import KeyPressEvent +from prompt_toolkit.document import Document +from prompt_toolkit.key_binding import KeyBindings +from prompt_toolkit.layout.containers import HSplit, VSplit, Window +from prompt_toolkit.layout.layout import Layout +from prompt_toolkit.layout.controls import FormattedTextControl +from prompt_toolkit.styles import Style +from prompt_toolkit.widgets import TextArea, Frame + + +__VERSION__ = "1.0" +NS_TO_MS = 1000000 + + +class BufferedLog: + """Buffered Log reads file on the fly keeping it open and returning lines on demand. + + :ivar file_path: path to the file + :ivar block_size: size of one read block + :ivar current_position: current position in the log + :ivar end_position: last position in the file + :ivar file: opened file + """ + def __init__(self, file_path: str, block_size: int = 1024): + """Initializes the buffered log + + :param file_path: path to the file + :param block_size: size of the read block + """ + self.file_path: str = file_path + self.block_size: int = block_size + self.current_position: int = 0 + self.end_position: int = 0 + self.file: Optional[TextIO] = None + + def __enter__(self) -> BufferedLog: + """Entering the context + + File is opened, and we infer the start and ending position + """ + self.file = open(self.file_path, "r", encoding="utf-8") + self.file.seek(0, io.SEEK_END) + self.end_position = self.file.tell() + self.file.seek(0) + return self + + def __exit__(self, exc_type: type, exc_val: Exception, exc_tb: BaseException) -> None: + """Closes the file""" + assert self.file is not None + self.file.close() + + def read_next_line(self) -> str: + """Reads the next line in the log + + :return: next line in the buffer + """ + assert self.file is not None + if self.current_position >= self.end_position: + return "" + self.file.seek(self.current_position) + line = self.file.readline() + self.current_position = self.file.tell() + return line.strip() + + def read_previous_line(self) -> str: + """Reads the previous line in log + + :return: previous line in the buffer + """ + assert self.file is not None + block = "" + while self.current_position > 0: + to_read = min(self.block_size, self.current_position) + self.file.seek(self.current_position - to_read) + block += self.file.read(to_read) + self.current_position -= to_read + if "\n" in block: + lines = block.split("\n") + if len(lines) < 3: + continue + last_full_line = lines[-2] + self.current_position += ( + sum(len(line) + 1 for line in lines[:-2]) + len(lines[-2]) + 1 + ) + self.file.seek(self.current_position) + return last_full_line.strip() + return block.strip() + + def get_current_position(self) -> int: + """Returns the current position in the log + """ + assert self.file is not None + return self.file.tell() + + def move_current_position(self, position: int) -> None: + """Moves position in the log + + :param position: new position in the log + """ + assert self.file is not None + self.current_position = position + self.file.seek(position) + + def close(self): + """Closes the buffered log""" + assert self.file is not None + self.file.close() + + +@dataclass +class Event: + """Event represents a single line in the log + + :ivar timestamp: timestamp of the event + :ivar event: type of the event (either call or return) + :ivar tid: thread id + :ivar pid: process id + :ivar uid: uid of the event (function) + """ + timestamp: int + event: str + tid: int + pid: int + uid: str + + @classmethod + def from_line(cls, line: str) -> "Event": + """Parses the event from single line + + :param line: line from the log + :return: parsed event + """ + parts = line.split(":") + ts, evt = parts[0], parts[-1] + middle_parts = parts[2].split(')(') + tid, pid, uid = middle_parts[0], parts[1][1:], middle_parts[1][:-1] + return Event(int(ts), evt, int(tid), int(pid), uid) + + +def singleton_class(cls): + """Helper class for creating singleton objects""" + instances = {} + + def getinstance() -> object: + """Singleton instance""" + if cls not in instances: + instances[cls] = cls() + return instances[cls] + + return getinstance + + +@singleton_class +class State: + """Represents single state of the run + + :ivar current_line: currently highlighted line in the log + :ivar real_line: real number in the log + :ivar buffered_log: instance of buffered log + :ivar last_command: last executed command + :ivar current_timestamp: current timestamp in the log + :ivar first_timestamp: first timestamp in the log + :ivar stack: stack of the calls + """ + def __init__(self) -> None: + self.current_line: int = 0 # Tracks the currently highlighted line + self.real_line: int = 0 + self.buffered_log: Optional[BufferedLog] = None + self.last_command: str = "" + self.current_timestamp: int = 0 + self.first_timestamp : int= 0 + self.stack: list[str] = [] + + self._log_content: list[str] = [] + self._buffer_positions: list[int] = [] + self._buffer_size: int = 25 + self._buffer_log_start: int = 0 + self._buffer_log_end: int = 0 + + def get_content(self) -> list[str]: + """Returns current content of the log""" + return self._log_content + + def init_buffer(self, buffered_log: BufferedLog) -> None: + """Initializes the buffer from buffered log. + + :param buffered_log: buffered log + """ + self.buffered_log = buffered_log + self._buffer_log_start = 0 + for i in range(0, self._buffer_size): + self._log_content.append(self.buffered_log.read_next_line()) + self._buffer_positions.append(self.buffered_log.get_current_position()) + self.first_timestamp = int(self._log_content[0].split(":")[0]) + self.current_timestamp = self.first_timestamp + self._buffer_log_end = self.buffered_log.get_current_position() + + def move_window_forward(self) -> None: + """Moves window forward by one line""" + assert self.buffered_log is not None + self.real_line += 1 + if self.current_line <= (self._buffer_size - 6): + self.current_line = min(self.current_line + 1, self._buffer_size) + return + + self._log_content = self._log_content[1:] + self.buffered_log.move_current_position(self._buffer_log_end) + line = self.buffered_log.read_next_line() + self._log_content.append(line) + + self._buffer_log_start = self._buffer_positions[0] + self._buffer_log_end = self.buffered_log.get_current_position() + self._buffer_positions = self._buffer_positions[1:] + [self._buffer_log_end] + + def move_window_backward(self) -> None: + """Moves window back by one line""" + assert self.buffered_log is not None + self.real_line = max(self.real_line - 1, 0) + if self.current_line > 5 or self.real_line <= 5: + self.current_line = max(self.current_line - 1, 0) + return + + self._log_content = self._log_content[:-1] + self.buffered_log.move_current_position(self._buffer_log_start) + line = self.buffered_log.read_previous_line() + self._log_content = [line] + self._log_content + + self._buffer_log_start = self.buffered_log.get_current_position() - len(line) + 1 + self._buffer_log_end = self._buffer_positions[-1] + self._buffer_positions = [self._buffer_log_start] + self._buffer_positions[:-1] + + def process_event(self) -> None: + """Processes next event""" + event = Event.from_line(self._log_content[self.current_line]) + self.current_timestamp = int(event.timestamp) + if event.event == "call": + self.stack.append(event.uid) + else: + self.stack.pop() + + def undo_event(self) -> None: + """Undo current event""" + event = Event.from_line(self._log_content[self.current_line]) + self.current_timestamp = int(event.timestamp) + if event.event == "call": + self.stack.pop() + else: + self.stack.append(event.uid) + + +# Custom syntax highlighting +def get_colored_log() -> list[tuple[str, str]]: + """Returns coloured contents""" + current_state: State = State() + styled_lines = [] + for i, line in enumerate(current_state.get_content()): + if i == current_state.current_line: + # Apply a different background for the current line + styled_lines.extend([("class:current_line", line + "\n")]) + else: + styled_lines.extend(get_colored_log_line(line) + [("", "\n")]) + return styled_lines + + +def get_colored_log_line(line: str) -> list[tuple[str, str]]: + """Returns colored line + + :param line: current line + """ + event = Event.from_line(line) + return [ + ("class:timestamp", str(event.timestamp)), + ("class:text", ":("), + ("class:pid", str(event.pid)), + ("class:text", ":"), + ("class:tid", str(event.tid)), + ("class:text", ")("), + ("class:function", event.uid), + ("class:text", "):"), + (f"class:{event.event}", event.event), + ] + + +# Key bindings for the application +bindings = KeyBindings() + + +@bindings.add("c-c") +@bindings.add("c-q") +def _(event: KeyPressEvent) -> None: + """Quit application.""" + event.app.exit() + + +def format_time(time: int) -> str: + """Formats time + + :param time: formatted time + """ + if time < NS_TO_MS: + return f"{time / NS_TO_MS:.2f}ms" + else: + minutes, milliseconds = divmod(int(time / NS_TO_MS), 60) + seconds, milliseconds = divmod(milliseconds, 1000) + return f"{minutes:02d}:{seconds:02d}.{milliseconds:d}" + + +def get_stats() -> str: + """Returns statistics for current state""" + current_state: State = State() + data = [ + ["current event", f"{current_state.real_line}"], + ["current time", f"{format_time(current_state.current_timestamp - current_state.first_timestamp)}"], + ] + return tabulate.tabulate(data, headers=[], tablefmt="presto") + +def get_stack() -> list[tuple[str, str]]: + """Returns formatted stack""" + current_state: State = State() + lines = [] + for f in current_state.stack[::-1]: + lines.extend([("class:function", f), ("", "\n")]) + return lines + + +def create_app(buffered_log: BufferedLog) -> Application[Any]: + """Creates apllication for given buffered log + + :param buffered_log: buffered log + """ + current_state: State = State() + current_state.init_buffer(buffered_log) + + def process_command(buff): + current_state: State = State() + cmd = buff.text.strip().lower() + + if cmd == "": + cmd = current_state.last_command + + if cmd == "help": + terminal.text = "Commands: help, next, prev" + elif cmd in ("next", "n", "j"): + current_state.process_event() + current_state.move_window_forward() + elif cmd in ("prev", "p", "k"): + current_state.move_window_backward() + current_state.undo_event() + elif cmd in ("quit", "exit", "q"): + app.exit() + else: + terminal.text = f"Unknown command: {cmd}" + current_state.last_command = cmd + # Refresh log view to reflect changes + log_view.content = FormattedTextControl(get_colored_log) + buff.document = Document() # Clear the terminal input after command execution + return True + + # Define the layout + stack_view = Frame(title="Stack", body=Window(content=FormattedTextControl(get_stack))) + counter_view = Frame(title="Stats", body=Window(content=FormattedTextControl(get_stats))) + log_view = Frame(title="Log", body=Window(content=FormattedTextControl(get_colored_log))) + state_view = Frame( + title="State", + body=HSplit([stack_view, counter_view]), + ) + terminal = TextArea( + prompt="> ", multiline=False, wrap_lines=False, accept_handler=process_command + ) + root_container = HSplit( + [ + VSplit([log_view, state_view]), + terminal, + ] + ) + + # Define styles + style = Style( + [ + ("timestamp", "#ff595e"), + ("tid", "#ff924c"), + ("pid", "#ffca3a"), + ("function", "#8ac926"), + ("call", "#1982c4"), + ("return", "#6a4c93"), + ("current_line", "bg:#0044ff #ffffff"), + ("text", ""), + ] + ) + + # Create the application + app: Application[Any] = Application( + layout=Layout(root_container), key_bindings=bindings, style=style, full_screen=True + ) + return app + + +def launch(): + """Launches logki""" + if len(sys.argv) == 2 and sys.argv[1] == '--version': + print(__VERSION__) + sys.exit(0) + elif len(sys.argv) == 2: + with BufferedLog(sys.argv[1]) as buffered_log: + application = create_app(buffered_log) + application.run() + else: + print("usage: ./logki.py .log") + sys.exit(1) + + +if __name__ == "__main__": + launch() diff --git a/pyproject.toml b/pyproject.toml new file mode 100755 index 0000000..010b6a8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,124 @@ +[build-system] +requires = [ + "setuptools >= 40.6.0", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +py-modules = ['logki'] +package-dir = {'logki' = 'logki'} + +[tool.setuptools.packages.find] +where = ['.'] +include = [ + 'logki', + 'logki*' +] +namespaces = true + +[tool.setuptools.package-data] +logki = [ +] + +[project] +name = "logki" +description = "logki: Log Analysis Kit" +requires-python = ">=3.9" +readme = "README.md" +license = { file = "LICENSE" } +authors = [ + {name = "Tomas Fiedor", email = "TomasFiedor@gmail.com"}, +] +dependencies = [ + # Build + + # Other + "prompt_toolkit>=3.0.43", + + # Plotting / visualization / output + "tabulate>=0.9", +] +dynamic = ["version"] + +[project.optional-dependencies] +docs = [ + # Sphinx 7.2 dropped support for Python 3.8 + "Sphinx>=7.1", + "sphinx-click>=5.0", +] +lint = [ + "black>=22.1.0", + "pylint>=2.17", +] +test = [ + "pytest>=7.4", + "pytest-cov>=4.1", + "tox>=4.9.0", +] +typing = [ + "mypy>=1.5", + "mypy-extensions>=1.0", + "typing-extensions>=4.7", + "types-tabulate>=0.9", +] + +[project.urls] +Repository = "https://github.com/Perfexionists/logki.git" +Changelog = "https://github.com/Perfexionists/logki/blob/master/CHANGELOG.rst" + +[project.scripts] +logki = "logki.app:launch" + +# Mypy configuration +# ---------------------- +[tool.mypy] +exclude = [ + ".git", + ".mypy_cache", + ".tox", + "build", + "docs", + "logki.egg-info", + "venv", +] +disallow_incomplete_defs = true +disallow_any_generics = true +no_implicit_optional = true +no_implicit_reexport = true +strict_equality = true +warn_redundant_casts = true +warn_unused_ignores = true +ignore_missing_imports = true + +# Pytest configuration +# -------------------- +[tool.pytest.ini_options] +addopts = "-p no:warnings -p no:logging" +norecursedirs = [ + "case-studies", + "venv", + "docs", + "*.egg-info", + ".git", + ".tox", + "build", + ".mypy_cache", +] + +# Coverage configuration +# ---------------------- +[tool.coverage.run] +source = [ + "logki", +] + +# Formatting configuration +# ---------------------- +[tool.black] +target-version = [ + "py39", + "py310", + "py311" +] +line-length = 100 \ No newline at end of file diff --git a/tests/test_logki.py b/tests/test_logki.py new file mode 100755 index 0000000..155c217 --- /dev/null +++ b/tests/test_logki.py @@ -0,0 +1,23 @@ +"""Basic tests for logki""" + +# Standard Imports +import os + +# Third-Party Imports +from prompt_toolkit.input import create_pipe_input +from prompt_toolkit.output import DummyOutput + +# Logki imports +import logki.app as logki + + +def test_app(): + with create_pipe_input() as pipe_input: + pipe_input.send_text('q\n') + with logki.BufferedLog(os.path.join(os.path.dirname(__file__), "workloads", "example.log")) as buffered_log: + app = logki.create_app(buffered_log) + app.input = pipe_input + app.output = DummyOutput() + + # Run the application + app.run() diff --git a/tests/workloads/example.log b/tests/workloads/example.log new file mode 100755 index 0000000..57d4bf9 --- /dev/null +++ b/tests/workloads/example.log @@ -0,0 +1,222 @@ +449651305717147:(21845:21845)(kfree):call +449651305724100:(21845:21845)(kfree):return +449651305725579:(21845:21845)(kfree):call +449651305727153:(21845:21845)(__kmem_cache_free):call +449651305728525:(21845:21845)(__kmem_cache_free):return +449651305800008:(21845:21845)(kfree):return +449651305812030:(21845:21845)(kmem_cache_free):call +449651305821701:(21845:21845)(kmem_cache_free):return +449651305830381:(21845:21845)(syscall_exit_to_user_mode_prepare):call +449651305839140:(21845:21845)(syscall_exit_work):call +449651305849913:(21845:21845)(__audit_syscall_exit):call +449651305852432:(21845:21845)(__audit_syscall_exit):return +449651305854838:(21845:21845)(syscall_exit_work):return +449651305857253:(21845:21845)(syscall_exit_to_user_mode_prepare):return +449651305860482:(21845:21845)(exit_to_user_mode_prepare):call +449651305863155:(21845:21845)(_raw_spin_lock_irq):call +449651305865704:(21845:21845)(_raw_spin_lock_irq):return +449651305867916:(21845:21845)(_raw_spin_unlock_irq):call +449651305870599:(21845:21845)(_raw_spin_unlock_irq):return +449651305874335:(21845:21845)(__fput):call +449651305877772:(21845:21845)(__cond_resched):call +449651305879997:(21845:21845)(__cond_resched):return +449651305883346:(21845:21845)(mutex_lock):call +449651305884906:(21845:21845)(__cond_resched):call +449651305886964:(21845:21845)(__cond_resched):return +449651305889290:(21845:21845)(mutex_lock):return +449651305891884:(21845:21845)(_raw_spin_lock_irqsave):call +449651305893291:(21845:21845)(_raw_spin_lock_irqsave):return +449651305896600:(21845:21845)(_raw_spin_lock_irqsave):call +449651305897845:(21845:21845)(_raw_spin_lock_irqsave):return +449651305904870:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305907734:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305910259:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305915942:(21845:21845)(irq_enter_rcu):call +449651305921833:(21845:21845)(irqtime_account_irq):call +449651305925693:(21845:21845)(irqtime_account_irq):return +449651305929083:(21845:21845)(irq_enter_rcu):return +449651305936148:(21845:21845)(_raw_spin_lock_irqsave):call +449651305940816:(21845:21845)(_raw_spin_lock_irqsave):return +449651305947899:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305950353:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305952634:(21845:21845)(irq_exit_rcu):call +449651305955607:(21845:21845)(irqtime_account_irq):call +449651305958536:(21845:21845)(irqtime_account_irq):return +449651305960003:(21845:21845)(idle_cpu):call +449651305961408:(21845:21845)(idle_cpu):return +449651305962940:(21845:21845)(irq_exit_rcu):return +449651305964981:(21845:21845)(irq_enter_rcu):call +449651305966218:(21845:21845)(irqtime_account_irq):call +449651305967360:(21845:21845)(irqtime_account_irq):return +449651305968847:(21845:21845)(irq_enter_rcu):return +449651305970808:(21845:21845)(_raw_spin_lock_irqsave):call +449651305972420:(21845:21845)(_raw_spin_lock_irqsave):return +449651305974211:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305976131:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305978135:(21845:21845)(irq_exit_rcu):call +449651305979253:(21845:21845)(irqtime_account_irq):call +449651305981001:(21845:21845)(irqtime_account_irq):return +449651305982200:(21845:21845)(idle_cpu):call +449651305983705:(21845:21845)(idle_cpu):return +449651305984769:(21845:21845)(irq_exit_rcu):return +449651305986522:(21845:21845)(irq_enter_rcu):call +449651305988310:(21845:21845)(irqtime_account_irq):call +449651305990191:(21845:21845)(irqtime_account_irq):return +449651305991169:(21845:21845)(irq_enter_rcu):return +449651305992998:(21845:21845)(_raw_spin_lock_irqsave):call +449651305994149:(21845:21845)(_raw_spin_lock_irqsave):return +449651305995996:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305997094:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305999290:(21845:21845)(irq_exit_rcu):call +449651306000856:(21845:21845)(irqtime_account_irq):call +449651306002263:(21845:21845)(irqtime_account_irq):return +449651306003488:(21845:21845)(idle_cpu):call +449651306004589:(21845:21845)(idle_cpu):return +449651306005970:(21845:21845)(irq_exit_rcu):return +449651306007730:(21845:21845)(irq_enter_rcu):call +449651306008978:(21845:21845)(irqtime_account_irq):call +449651306010408:(21845:21845)(irqtime_account_irq):return +449651306011786:(21845:21845)(irq_enter_rcu):return +449651306013923:(21845:21845)(_raw_spin_lock_irqsave):call +449651306015042:(21845:21845)(_raw_spin_lock_irqsave):return +449651306017104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306018366:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306020129:(21845:21845)(irq_exit_rcu):call +449651306021165:(21845:21845)(irqtime_account_irq):call +449651306022889:(21845:21845)(irqtime_account_irq):return +449651306024142:(21845:21845)(idle_cpu):call +449651306025704:(21845:21845)(idle_cpu):return +449651306026937:(21845:21845)(irq_exit_rcu):return +449651306028874:(21845:21845)(irq_enter_rcu):call +449651306030361:(21845:21845)(irqtime_account_irq):call +449651306032054:(21845:21845)(irqtime_account_irq):return +449651306033084:(21845:21845)(irq_enter_rcu):return +449651306035164:(21845:21845)(_raw_spin_lock_irqsave):call +449651306036445:(21845:21845)(_raw_spin_lock_irqsave):return +449651306038223:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306039225:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306040914:(21845:21845)(irq_exit_rcu):call +449651306042387:(21845:21845)(irqtime_account_irq):call +449651306043823:(21845:21845)(irqtime_account_irq):return +449651306045094:(21845:21845)(idle_cpu):call +449651306046799:(21845:21845)(idle_cpu):return +449651306048282:(21845:21845)(irq_exit_rcu):return +449651306049905:(21845:21845)(irq_enter_rcu):call +449651306051063:(21845:21845)(irqtime_account_irq):call +449651306052677:(21845:21845)(irqtime_account_irq):return +449651306054156:(21845:21845)(irq_enter_rcu):return +449651306056001:(21845:21845)(_raw_spin_lock_irqsave):call +449651306057348:(21845:21845)(_raw_spin_lock_irqsave):return +449651306058914:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306060465:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306061750:(21845:21845)(irq_exit_rcu):call +449651306063251:(21845:21845)(irqtime_account_irq):call +449651306064998:(21845:21845)(irqtime_account_irq):return +449651306066683:(21845:21845)(idle_cpu):call +449651306067866:(21845:21845)(idle_cpu):return +449651306068994:(21845:21845)(irq_exit_rcu):return +449651306070886:(21845:21845)(irq_enter_rcu):call +449651306072286:(21845:21845)(irqtime_account_irq):call +449651306073883:(21845:21845)(irqtime_account_irq):return +449651306075087:(21845:21845)(irq_enter_rcu):return +449651306077129:(21845:21845)(_raw_spin_lock_irqsave):call +449651306078428:(21845:21845)(_raw_spin_lock_irqsave):return +449651306080104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306081289:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306082424:(21845:21845)(irq_exit_rcu):call +449651306084461:(21845:21845)(irqtime_account_irq):call +449651306085655:(21845:21845)(irqtime_account_irq):return +449651306087347:(21845:21845)(idle_cpu):call +449651306088245:(21845:21845)(idle_cpu):return +449651306089812:(21845:21845)(irq_exit_rcu):return +449651306091789:(21845:21845)(irq_enter_rcu):call +449651306093231:(21845:21845)(irqtime_account_irq):call +449651306094161:(21845:21845)(irqtime_account_irq):return +449651306095499:(21845:21845)(irq_enter_rcu):return +449651306097027:(21845:21845)(_raw_spin_lock_irqsave):call +449651306098434:(21845:21845)(_raw_spin_lock_irqsave):return +449651306100032:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306101322:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306103370:(21845:21845)(irq_exit_rcu):call +449651306105076:(21845:21845)(irqtime_account_irq):call +449651306106109:(21845:21845)(irqtime_account_irq):return +449651306107586:(21845:21845)(idle_cpu):call +449651306108988:(21845:21845)(idle_cpu):return +449651306110299:(21845:21845)(irq_exit_rcu):return +449651306112028:(21845:21845)(irq_enter_rcu):call +449651306113911:(21845:21845)(irqtime_account_irq):call +449651306115148:(21845:21845)(irqtime_account_irq):return +449651306116955:(21845:21845)(irq_enter_rcu):return +449651306118563:(21845:21845)(_raw_spin_lock_irqsave):call +449651306120193:(21845:21845)(_raw_spin_lock_irqsave):return +449651306121698:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306123240:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306124573:(21845:21845)(irq_exit_rcu):call +449651306126425:(21845:21845)(irqtime_account_irq):call +449651306128107:(21845:21845)(irqtime_account_irq):return +449651306129739:(21845:21845)(idle_cpu):call +449651306131113:(21845:21845)(idle_cpu):return +449651306132204:(21845:21845)(irq_exit_rcu):return +449651306134263:(21845:21845)(irq_enter_rcu):call +449651306135755:(21845:21845)(irqtime_account_irq):call +449651306137490:(21845:21845)(irqtime_account_irq):return +449651306138257:(21845:21845)(irq_enter_rcu):return +449651306139967:(21845:21845)(_raw_spin_lock_irqsave):call +449651306141326:(21845:21845)(_raw_spin_lock_irqsave):return +449651306142941:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306143993:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306146020:(21845:21845)(irq_exit_rcu):call +449651306147271:(21845:21845)(irqtime_account_irq):call +449651306149021:(21845:21845)(irqtime_account_irq):return +449651306150343:(21845:21845)(idle_cpu):call +449651306151936:(21845:21845)(idle_cpu):return +449651306153351:(21845:21845)(irq_exit_rcu):return +449651306155400:(21845:21845)(irq_enter_rcu):call +449651306156749:(21845:21845)(irqtime_account_irq):call +449651306158440:(21845:21845)(irqtime_account_irq):return +449651306159673:(21845:21845)(irq_enter_rcu):return +449651306160914:(21845:21845)(_raw_spin_lock_irqsave):call +449651306161783:(21845:21845)(_raw_spin_lock_irqsave):return +449651306163150:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306164098:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306165525:(21845:21845)(irq_exit_rcu):call +449651306166404:(21845:21845)(irqtime_account_irq):call +449651306167628:(21845:21845)(irqtime_account_irq):return +449651306169374:(21845:21845)(idle_cpu):call +449651306170457:(21845:21845)(idle_cpu):return +449651306171490:(21845:21845)(irq_exit_rcu):return +449651306172920:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306174229:(21845:21845)(_raw_spin_lock_irqsave):call +449651306175561:(21845:21845)(_raw_spin_lock_irqsave):return +449651306176842:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306177852:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306179116:(21845:21845)(mutex_unlock):call +449651306180884:(21845:21845)(mutex_unlock):return +449651306184624:(21845:21845)(_raw_spin_lock):call +449651306186282:(21845:21845)(_raw_spin_lock):return +449651306188480:(21845:21845)(_raw_spin_unlock):call +449651306189664:(21845:21845)(_raw_spin_unlock):return +449651306192308:(21845:21845)(dput):call +449651306194809:(21845:21845)(__cond_resched):call +449651306196639:(21845:21845)(__cond_resched):return +449651306198886:(21845:21845)(dput):return +449651306201957:(21845:21845)(mntput):call +449651306203024:(21845:21845)(mntput):return +449651306204139:(21845:21845)(kmem_cache_free):call +449651306205971:(21845:21845)(__slab_free):call +449651306208669:(21845:21845)(__slab_free):return +449651306210733:(21845:21845)(kmem_cache_free):return +449651306212495:(21845:21845)(__call_rcu_common.constprop.0):call +449651306214769:(21845:21845)(rcu_nocb_try_bypass):call +449651306217920:(21845:21845)(rcu_segcblist_pend_cbs):call +449651306219060:(21845:21845)(rcu_segcblist_pend_cbs):return +449651306220460:(21845:21845)(rcu_nocb_try_bypass):return +449651306224060:(21845:21845)(rcu_segcblist_enqueue):call +449651306226501:(21845:21845)(rcu_segcblist_enqueue):return +449651306228010:(21845:21845)(__call_rcu_common.constprop.0):return +449651306229147:(21845:21845)(__fput):return +449651306232040:(21845:21845)(__cond_resched):call +449651306235163:(21845:21845)(__cond_resched):return +449651306238018:(21845:21845)(mem_cgroup_handle_over_high):call +449651306240262:(21845:21845)(mem_cgroup_handle_over_high):return +449651306242616:(21845:21845)(exit_to_user_mode_prepare):return diff --git a/tox.ini b/tox.ini new file mode 100755 index 0000000..6393f28 --- /dev/null +++ b/tox.ini @@ -0,0 +1,41 @@ +[tox] +requires = + tox>=4 +env_list = + py{3.9, 3.10, 3.11} + lint + typing + docs + +[testenv] +description = Run logki tests +usedevelop=True +allowlist_externals = make +extras = test +commands = + make test-ci + +[testenv:lint] +description = Run code style checker Pylint +allowlist_externals = make +extras = lint +commands = + make lint + +[testenv:typing] +# We can't skip install as some of our dependencies ship type hints directly in their core package +# and not as a standalone typeshed package. +description = Run static type checker Mypy +allowlist_externals = make +extras = typing +commands = + make check + +[testenv:docs] +description = Generate Sphinx HTML documentation +allowlist_externals = make +extras = docs +commands = + make docs +[pytest] +norecursedirs = docs *.egg-info .git .tox build .mypy_cache