Note: for a more formal introduction please readBashing irreproducibility withshournalon bioRxiv.
TL;DR:
strace -f -e close $cmd
but without the limitations imposed by ptrace-based solutionsand a lot faster (Overhead).More details please:
Using your shell's history is nice. But sometimes you want more:
shournal provides the answer to these questions whilecausing only a negligible overhead.
Besides its ability to monitor a whole process tree for fileevents it can be integrated really tight into the shell -you won't even notice it (;
See also: shell-integration
Besides output on the command-line in a human-readable format (or JSON)you can export (parts of) your command-history intoa standalone html-file where it is displayed in an interactivetime-line-plot. Further miscellaneous statistics are displayed inbar-plots, e.g. the commands with most file-modifications (see also above gif).
Using the external softwareshournal-to-snakemakean observed shell-command-series can be directly transformed into rules forthe Snakemake workflow engine,a tool to create reproducible and scalable data analyses.
shournal runs only on GNU/Linux.
Please note: below examples make use of theshell-integration.
Otherwise shournal --exec $cmd
andother boilerplate-code would have been necessary.
Instead of printing the --query
-results to terminal, you can also createfancy html-plots, by appending --output-format html -o out.html
.Use an ordinary web-browser for display.
$ SHOURNAL_ENABLE # monitor all commands using the shell-integration
$ echo hi > foo
$ shournal --query --wfile foo
Command id 1 returned 0 - 14.05.19 10:19 : echo hi > foo
Written file(s):
/home/user/foo (3 bytes) Hash: 15349503233279147316
$ ./test.sh
$ shournal -q --history 1
Command id 2 returned 0 - 14.05.19 14:01 : ./test.sh
Read file(s):
/home/user/test.sh (213 bytes) id 1
#!/usr/bin/env bash
echo 'Hello world'
shournal --query --command-working-dir "$PWD"
shournal --query --shell-session-id $uuid
shournal --query --help
For Debian/Ubuntu-based distributions .deb-packages are available on therelease-page.Three different editions are provided for different use-cases: most users willwant to install shournal on a real host (or virtual machine) andshournal-docker inside Docker(or another container platform).shournal-fanotify does not contain the kernel backend andis targeted at institutions where the usage of out-of-tree kernel-modulesis discouraged.
Only LTS-releases are officially supported, the packages are known to work onDebian 9 (Stretch), Debian 10 (Buster), Ubuntu 18.04 (Bionic) and Ubuntu 20.04 (Focal).Install deb-packages as usual, e.g. sudo apt install ./shournal_2.2_amd64.deb
An update of shournal should be performed after all users havelogged out, because the shell integrations need to be resourced.Further in case of the kernel module backend unloading the oldversion stops all running observations.
After installation:Depending on your distribution, additional steps might be necessary toenable the (recommended) uuidd-daemon. If systemd is in use, onemay need to:
systemctl enable uuidd
systemctl start uuidd
Add yourself or other users to the group shournalk: sudo adduser $USER shournalk
(relogin to take affect).
You may override this group:
mkdir -p /etc/shournal.d/
echo GROUPNAME > /etc/shournal.d/kgroup
replacing GROUPNAME with the value of your choice. This rule takesinto effect the next time shournal's kernel module is loaded ( socall e.g. modprobe -r shournalk; modprobe shournalk
or reboot).
To enable the shell-integration:
source /usr/share/shournal/SOURCE_ME.bash
source /usr/share/shournal/SOURCE_ME.zsh
and run SHOURNAL_ENABLE
afterwards.
More details and advanced options (logging commands executed via ssh)can be found here.
Please refer to the instructions found within thecompile-README.
--wfile
commandline-query-option, shournal finds the stored commandby content (size, hash) and mtime, not by its name.For the name, --wname
can be used.More concrete:
shournal --exec sh -c 'echo foo > bar; mv bar bar_old'
--wfile
-option) yields exactlythe given command, however, --wname bar_old
does not work(--wname bar
of course works). To use the bar_old file name(and not content) as basis for a successful query, in this case--command-text -like '%bar_old%'
can be used.fanotify_mark: failed to add path /foobar ... Permission denied
.This message might be printed on executing a command with shournal.Most probably the administrator mounted a filesystem object for which you don't havepermissions, thus you cannot monitor file events.In this case you cannot perform file operations at this pathanyway, so it should be safe to silence this warning by adding thepath within the config-file in section [mounts]
. If you want to ignore allfanotify_mark permission errors, you can set the flag in section[mounts]
:
[mounts]
ignore_no_permission = true
shournal stores a self-documenting config-file typically at~/.config/shournalwhich is created on first run. It can be edited either directly witha plain text editor or via --edit-cfg
.For completeness, the most important points are listed here as well.
Write- and read events can be configured, so only events occurring atspecific (include-)paths are stored. Put each path into a separateline, all paths being enclosedby triple quotes:
include_paths = '''
/home/me
/media
'''
Each exclude_path should be a sub-path of an include path.
Note that by default, thereis a limit on the number of logged events per command (max_event_count).Read files (e.g. scripts) can further be configuredto be stored within shournal's database.Files are only stored, if the configured max. file-size, file extension(e.g. sh) and mimetype (e.g. application/x-shellscript) matches.To find a mimetype for a given file you should use shournal --print-mime test.sh
.The correspondence of mimetype and file extensionis explained in more detail within the config-file.Further, at your wish, read files are only stored if you have write permission for them(not only read) - often system-provided scripts (owned by root) are not of particularinterest.
shournal will not store more read files per command, than max_count_of_files.Matching files coming first have precedence.
To use shournal within Docker (or another container platform),depending on the backend the following steps are necessary:
kernel module backend
Install shournal on the host and shournal-docker inside the container.For unprivileged containers sysfs is mounted readonly. In this casecreate a bindmount from /sys/kernel/shournalk_root to/tmp/shournalk-sysfs, e.g. docker run ... -v /sys/kernel/shournalk_root:/tmp/shournalk-sysfs
.
fanotify backend
Install shournal-docker (or shournal-fanotify) inside docker.For unprivileged containers the capabilities SYS_ADMIN, SYS_PTRACE andSYS_NICE are required, e.g. docker run ... --cap-add SYS_ADMIN --cap-add SYS_PTRACE --cap-add SYS_NICE
.
You may need to configure the backend.
shournal provides two backends, a custom kernel module and fanotify.The kernel module is used by default, except the shournal-fanotifyedition is installed, where only the fanotify backend isavailable. In general it is recommended to stick with the kernel moduleas it is faster and has less interference with the process environment -for example no new mount namespaces have to be created and no filedescriptor inheritance is necessary to wait for the end of a processtree. See also:shell-integration.
If both backends are installed you may configure the default one globallyby creating the file /etc/shournal.d/backend
or for each user by creating~/.config/shournal/backend
with content ko
or fanotify
.
Depending on the file-activity of the observed commands, shournal'sdatabase will sooner or later grow. When you feel that enough timehas passed and want to get rid of old events, this can be done by e.g.shournal --delete --older-than 1y
which deletes all commands (and file-events) older than one year.More options are available, see alsoshournal --delete --help
-o allow_root
to the sshfs-options,otherwise permission errors during fanotify_mark
are raised.See also: https://serverfault.com/a/188896In the kernel module it is ensured that each user is only allowed tomonitor his/her own processes. Further, the kernel thread, which processesfile events, runs with effective caller credentials and checksallowed accesses on a per-file basis. Memory allocations are cgroup-aware,even for reading (in case of hashing) and writing (in case of logging)files.
shournal-run-fanotify is a so called "setuid"-program: whenever a regular user calls it, it runswith root-permissions in the first place. As soon as possible, it runs effectively with userpermissions though.It must be setuid for two reaons:
Processes can communicate via IPC (inter-process-communication).If the observed process A instructs the not observed process Bvia IPC to modify a file, the filesystem-event is not registered byshournal.
For performance reasons, all files opened with write-permissionsare reported as written by shournal, irrespective of whetherthe process actually wrote to it. By using file size and content (hash)you should be able to cover those cases.
The provided timestamp is determined shortly after a file wasclosed. Note that it is possible that some other process haswritten to it in between. This however is only aproblem, if that other process was itself not observed.
Whether memory mapped (see mmap(2) ) file-events are reported correctlydepends on when the underlying file-descriptor is closed. It is thusapplication dependent and does not work in general.
The file observation only works, if the process does not unshare themount-namespace itself, e.g. monitoring a program startedvia flatpak fails.For further limitations please visit the fanotify manpage.
shournal attempts to deterministically associate files and shell-commands without changing the users workflow. Under Linux file operations areperformed by the kernel, tracing these operations thus requires OS-level support.During the execution of a shell-command, shournal instruments the kernel totrace files used by the shell-process and any of it’s descendant processes. Moreparticular, to keep the tracing-overhead low, only the closing of files is tracedand (meta-)data collection starts afterwards in an asynchronous manner.
shournalk as a kernel module runs directly in kernel space and is based ontracepointsand theftrace-frameworkwhich basically allow for custom code to be run at certain kernelexecution paths without recompilation of the kernel itself. Only threeevents are traced: closing of files, fork and exit. (Meta-)data collectionalso takes place entirely in kernel space.
The fanotify backend employs the kernel-nativefanotify filesystem APIto register for close-events of wholemount-points which are isolated against unrelatedprocesses using unsharedmount namespaces.shournal thereby ensures that all file-operations during the execution of a shell-command refer to the same, unique mount namespace. While the process-filteringtakes place in kernel space — so only file-events of observed processesare copied to user-space — the (meta-)data collection happens in userspace.
File tracing imposes a runtime overhead.A detailed performance evaluation may follow soon. For now:We measured the following command executions with shournal v2.5:
The benchmark involves tracing, (meta-)data collection and saving toa binary temporary file. As this file can be kept indefinitely, thefinal storing into the SQL-database is not part of the measurement.
The relative runtime-overheads are shown in below table,strace listed for comparison with ptrace-based solutions:
Backend | compile | checkout | cp |
---|---|---|---|
kernel module | 0,03% | 0,4% | 0,35% |
fanotify | 0,4% | 2,4% | 28,7% |
(strace) | 125% | 93% | 494% |
For the cp
benchmark, where ~120.000 file-events occurredin ~4 seconds, the runtime overhead of the fanotify backend becomessignificant. Note that many file-events in short time constitute aworst-case. Where performance is critical, the kernel module backendshould be used.
The storage overhead largely depends on configuration, e.g. the numberof stored scripts and file-metadata is limited by default, to avoid e.g.a backup-script from flooding the database. For the cp-testthe average disk-usage per file-event is approx. 174 bytes which alreadyincludes indexes to speed up queries. So one GiB of disk-space issufficient for approx. 6 million events. Based on the experience of real-worldusers the database is typically not larger than a few hundred megabytesafter months of usage.
shournal makes use of great tools and libraries, most importantly the Qt-framework,xxhash, tsl::ordered_map and cmake and also the Linux-Kernel's fanotify.For the html-plot d3js, jquery, popper.js, bootstrap, webpackand others are used.
Thanks to the developers!
The project arose in the Hoffmann ResearchGroup: Computational Biology of Agingat the Fritz Lipmann Institute in Jena (Germany).Special thanks toSteve Hoffmannand Konstantin Riege - without you this projectcouldn't have been accomplished.
The whole project is licensed under the GPL, v3 or later(see LICENSE file for details)
except
kernel/
which is licensed underthe GNU General Public License version 2 only.extern/
→ Please refer to the licenses within theirrespective directories.html-export/dist/main.js
→ the licenses arestored in html-export/dist/main.licenses.txt
.Copyleft (C) 2021, Tycho Kirchner
File An API to read, write and navigate file system hierarchies, based on the W3C File API. Objects DirectoryEntry DirectoryReader File FileEntry FileError FileReader FileSystem FileTransfer FileTrans
fis.file~ File new File(propsopt) File,fis 编译过程中,文件会被此类进行封装,对于文件的操作,都是通过此类来完成。 Parameters: Name Type Attributes Description path... String 文件路径,可以作为多个参数输入,多个参数会被 / 串联起来。 props Object <optional> 可以默认给文
fis. file 用来创建 File 对象, 更多细节请查看 File 说明。 var file = fis.file(root, 'static/xxx.js'); Source: file.js, line 690 See: File 类说明 Classes File Members (static) wrap 用来包裹文件,输入可以是路径也可以是文件对象,输出统一为文件对象。 Source
文件操作. 支持 安装 $ npm install universal-file --save 方法 getInfo(options) 获取文件信息。 参数 属性 类型 默认值 必选 描述 支持 filePath String √ 文件路径 digestAlgorithm String md5 x 摘要算法,支持 md5 和 sha1 getSavedInfo(options) 获取保存的文件信息
This plugin implements a File API allowing read/write access to files residing on the device. This plugin is based on several specs, including : The HTML5 File API http://www.w3.org/TR/FileAPI/ The (n
类名: Imi\Util\File 文件相关工具类 方法 enum 方法返回一个迭代器对象。 // 枚举当前目录及所有子目录中的文件,不包含.和.. foreach(File::enum(__DIR__) as $fileName) { echo (string)$fileName, PHP_EOL; } enumPHPFile 方法返回一个迭代器对象。 // 枚举当前目录及所有子目录中
配置 <?php return [ 'caches' => [ // 缓存名称 'alias1' => [ // 缓存驱动类 'handlerClass' => \Imi\Cache\Handler\File::class, // 驱动实例配置
描述: 描述一个文件。 别名: @fileoverview @overview Overview(概述) @file标签提供文件的说明。在文件开头的JSDoc注释部分使用该标签。 Example (例子) 例如,文件描述: /** * @file Manages the configuration settings for the widget. * @author Rowina Sanela