├── .github └── FUNDING.yml ├── .travis.yml ├── LICENSE ├── README.md ├── etc └── init.d │ └── strace-docker ├── extract ├── install └── strace-docker /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: amrabed 2 | patreon: amrabed 3 | custom: ["https://paypal.me/AmrAbed"] 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | 3 | install: sudo ./install 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Amr Abed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/amrabed/strace-docker.svg?branch=master)](https://travis-ci.org/amrabed/strace-docker) 2 | [![GitHub issues](https://img.shields.io/github/issues/amrabed/strace-docker.svg)](https://github.com/amrabed/strace-docker/issues) 3 | [![GitHub (pre-)release](https://img.shields.io/github/release/amrabed/strace-docker/all.svg)](https://github.com/amrabed/strace-docker/releases) 4 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 5 | 6 | # strace-docker 7 | Trace system calls from Docker containers running on the system* 8 | 9 | 10 | ## Usage 11 | ### Install 12 | git clone https://github.com/amrabed/strace-docker && sudo ./strace-docker/install 13 | 14 | To check if `strace-docker` is successfully installed and running, use `service strace-docker status` 15 | 16 | ### Tracing 17 | `strace-docker` is automatically triggered by [`docker events`](https://docs.docker.com/engine/reference/commandline/events) to monitor any new Docker container. The resulting trace of system calls is written to a new file at `/var/log/strace-docker/`. File name will be `$id-$image-$timestamp` where `$id` is the container ID, `$image` is the container image, and `$timestamp` is the time the container started. You can see full log of monitored containers at `/var/log/strace-docker/log`. 18 | 19 | [![How to use the strace-docker tool](https://img.youtube.com/vi/iWywV_4Y34E/0.jpg)](https://www.youtube.com/watch?v=iWywV_4Y34E) 20 | 21 | 22 | ## Known Issues 23 | - `strace-docker` does not currently stop tracing process automatically when container is stopped. 24 | - `strace-docker` does not resume tracing to the same file on container restart. 25 | - `strace-docker` relies internally on [`Sysdig`](https://sysdig.com) which limits the number of monitoring processes to 5 by default. Due to `strace-docker` not killing/stopping monitoring processes automatically, `strace-docker` stops montioring new containers when 5 containrs are currently monitored. The user then needs to manually stop any `strace-docker` processes that are no longer needed (i.e., whose containers are not running anymore). 26 | 27 | All contributions are welcome :) 28 | 29 | 30 | * Implemented as part of my Ph.D. dissertation research. See [this paper](https://arxiv.org/abs/1611.03056) for more details 31 | -------------------------------------------------------------------------------- /etc/init.d/strace-docker: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: skeleton 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Run strace on any running Docker container 9 | ### END INIT INFO 10 | 11 | # Author: Amr Abed 12 | 13 | NAME=strace-docker 14 | DAEMON=/usr/bin/$NAME 15 | #DAEMON_ARGS="--options args" 16 | PIDFILE=/var/run/$NAME.pid 17 | SCRIPTNAME=/etc/init.d/$NAME 18 | 19 | # Exit if the package is not installed 20 | [ -x "$DAEMON" ] || exit 0 21 | 22 | # Read configuration variable file if it is present 23 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 24 | 25 | # Load the VERBOSE setting and other rcS variables 26 | # . /lib/init/vars.sh 27 | 28 | # Define LSB log_* functions. 29 | # Depend on lsb-base (>= 3.2-14) to ensure that this file is present 30 | # and status_of_proc is working. 31 | . /lib/lsb/init-functions 32 | 33 | # 34 | # Function that starts the daemon/service 35 | # 36 | do_start() 37 | { 38 | # Return 39 | # 0 if daemon has been started 40 | # 1 if daemon was already running 41 | # 2 if daemon could not be started 42 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ 43 | || return 1 44 | start-stop-daemon --start --quiet --background --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \ 45 | || return 2 46 | # Add code here, if necessary, that waits for the process to be ready 47 | # to handle requests from services started subsequently which depend 48 | # on this one. As a last resort, sleep for some time. 49 | } 50 | 51 | # 52 | # Function that stops the daemon/service 53 | # 54 | do_stop() 55 | { 56 | # Kill children first (not killed by start-stop-daemon) 57 | pkill -P $(cat $PIDFILE) 58 | # Return 59 | # 0 if daemon has been stopped 60 | # 1 if daemon was already stopped 61 | # 2 if daemon could not be stopped 62 | # other if a failure occurred 63 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 64 | RETVAL="$?" 65 | [ "$RETVAL" = 2 ] && return 2 66 | # Wait for children to finish too if this is a daemon that forks 67 | # and if the daemon is only ever run from this initscript. 68 | # If the above conditions are not satisfied then add some other code 69 | # that waits for the process to drop all resources that could be 70 | # needed by services started subsequently. A last resort is to 71 | # sleep for some time. 72 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 73 | [ "$?" = 2 ] && return 2 74 | # Many daemons don't delete their pidfiles when they exit. 75 | rm -f $PIDFILE 76 | return "$RETVAL" 77 | } 78 | 79 | # 80 | # Function that sends a SIGHUP to the daemon/service 81 | # 82 | do_reload() { 83 | # 84 | # If the daemon can reload its configuration without 85 | # restarting (for example, when it is sent a SIGHUP), 86 | # then implement that here. 87 | # 88 | start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME 89 | return 0 90 | } 91 | 92 | case "$1" in 93 | start) 94 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 95 | do_start 96 | case "$?" in 97 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 98 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 99 | esac 100 | ;; 101 | stop) 102 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 103 | do_stop 104 | case "$?" in 105 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 106 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 107 | esac 108 | ;; 109 | status) 110 | status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 111 | ;; 112 | #reload|force-reload) 113 | # 114 | # If do_reload() is not implemented then leave this commented out 115 | # and leave 'force-reload' as an alias for 'restart'. 116 | # 117 | #log_daemon_msg "Reloading $DESC" "$NAME" 118 | #do_reload 119 | #log_end_msg $? 120 | #;; 121 | restart|force-reload) 122 | # 123 | # If the "reload" option is implemented then remove the 124 | # 'force-reload' alias 125 | # 126 | log_daemon_msg "Restarting $DESC" "$NAME" 127 | do_stop 128 | case "$?" in 129 | 0|1) 130 | do_start 131 | case "$?" in 132 | 0) log_end_msg 0 ;; 133 | 1) log_end_msg 1 ;; # Old process is still running 134 | *) log_end_msg 1 ;; # Failed to start 135 | esac 136 | ;; 137 | *) 138 | # Failed to stop 139 | log_end_msg 1 140 | ;; 141 | esac 142 | ;; 143 | *) 144 | #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 145 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 146 | exit 3 147 | ;; 148 | esac 149 | 150 | : 151 | -------------------------------------------------------------------------------- /extract: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INPUT=./data 4 | OUTPUT=../output 5 | 6 | cd $INPUT 7 | 8 | [ -d $OUTPUT ] && rm -r $OUTPUT 9 | 10 | mkdir $OUTPUT 11 | 12 | for file in *; do 13 | [ $file == log ] && continue 14 | echo -n Extracting data from $file ... 15 | gawk '1{p=1} /% time/{p=0} p{match($2, "[a-z_]+", a)}{if(a[0]) print a[0]}' $file > $OUTPUT/"$file"_trace 16 | gawk -v n=$(($(wc -l < $file) - 1)) '/% time/{l=NR} l && NR>=l+2 && NR $OUTPUT/"$file"_count 17 | echo " done" 18 | done 19 | -------------------------------------------------------------------------------- /install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | # Install inotifywait 6 | if ! type inotifywait > /dev/null; then 7 | apt-get install -y inotify-tools 8 | fi 9 | 10 | # Install Docker 11 | if ! type docker > /dev/null; then 12 | wget -qO- https://get.docker.com/ | sh && usermod -aG docker $USER 13 | fi 14 | 15 | # Install Gawk 16 | if ! type gawk > /dev/null; then 17 | apt-get install -y gawk 18 | fi 19 | 20 | # Install Sysdig 21 | if ! type sysdig > /dev/null; then 22 | curl -s https://s3.amazonaws.com/download.draios.com/stable/install-sysdig | bash 23 | fi 24 | 25 | cp strace-docker /usr/bin 26 | cp etc/init.d/strace-docker /etc/init.d 27 | update-rc.d strace-docker defaults 28 | service strace-docker start 29 | 30 | -------------------------------------------------------------------------------- /strace-docker: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script runs strace on any newly-started Docker container 4 | # 5 | # Written by Amr S. Abed 6 | # 7 | # Last updated June 8, 2015 8 | 9 | cd "$(dirname "$0")" 10 | 11 | WORKDIR=/var/log/strace-docker 12 | 13 | [ ! -d $WORKDIR ] && mkdir $WORKDIR 14 | 15 | cd $WORKDIR && touch log 16 | 17 | docker events -f event=start >> log & 18 | 19 | while inotifywait -qq -e modify log; do 20 | new_line=$(tail -1 log) 21 | timestamp=$(echo $new_line | gawk '{tmp=substr($1, 0, 19)}{gsub(/:|-|T/,"",tmp)}{print tmp}') 22 | id=$(echo $new_line | gawk '{print substr($4, 0, 12)}') 23 | image=$(echo $new_line | gawk '{match($0, "image=([a-z/]+)", a)}{gsub(/\//, "_", a[1])}{print a[1]}') 24 | out_file=$id-$image-$timestamp 25 | sysdig -p"%thread.tid %evt.type" container.id=$id and evt.type!=switch > $out_file & 26 | done 27 | --------------------------------------------------------------------------------