Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ dokku-logging-supervisord plugin will run all process types (web, worker, etc.)

Additionally, it creates and binds a shared directory for each app from `/var/log/dokku/$APP` on the host machine to `/var/log/app` in the app's container. The supervisord config is setup to have each process in your Procfile send it's stdout and stderr to a separate file in that directory named `$PROCESS_NAME.$PROCESS_NUM.log`. Output for the `supervisord` process itself (startup/shutdown notices, etc) will be logged to a file named `supervisor.log` in the same log directory.

As the default `dokku logs` command will only show output from supervisord, additional log commands are provided:

logs:all <app> [-t] [process_name] Show all logs, including supervisord (-t follows)
logs:app <app> [-t] [process_name] Show all logs, exclusing supervisord (-t follows)
logs:supervisord <app> [-t] Show only supervisord log (-t follows)

The `logs:supervisord` command differs from the built-in `logs` command in that it specifically fetches it's output from `/var/log/dokku/$APP/supervisor.log` rather than the STDOUT of the main process in the container.

## Example

If you have an app `myapp` with a Procfile that looks like this:
Expand Down
40 changes: 31 additions & 9 deletions commands
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,35 @@
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x

PLUGIN_DIR=$(dirname $0)
. "$PLUGIN_DIR/lib/helpers"
source "$PLUGIN_DIR/functions"
source "$(dirname "$PLUGIN_DIR")/common/functions"

case "$1" in
logs:all)
shift 1
tail_logs all $@
;;

logs:app)
shift 1
tail_logs app $@
;;

logs:supervisord)
tail_logs all $2 $3 supervisor
;;

ps:scale)
echo "logging-supervisord plugin handles scaling, use the \"scale\"" \
"command instead of \"ps:scale\"."
exit 1
;;

scale)
if [[ -z $2 ]]; then
echo "Please specify an app to scale"
exit 1
fi
APP="$2"
IMAGE="dokku/$APP"
[[ -z $2 ]] && echo "Please specify an app to scale" && exit 1
verify_app_name "$2"
APP="$2";

REPO="$DOKKU_ROOT/$APP"
if [ ! -d "$REPO" ]; then
echo "No matching app: $APP"
Expand Down Expand Up @@ -39,13 +58,16 @@ case "$1" in

echo "Scaling app $APP:"
cat -n "$REPO/SCALE"
copy_to_container "$SCALEFILE" /app/SCALE
copy_to_container "$APP" "$SCALEFILE" /app/SCALE

dokku deploy "$APP"
;;
help)
cat && cat<<EOF
scale <app> TYPE1=NUM1 [TYPE2=NUM2 ...] Scale an app
logs:all <app> [-t] [process_name] Show all logs, including supervisord (-t follows)
logs:app <app> [-t] [process_name] Show all logs, exclusing supervisord (-t follows)
logs:supervisord <app> [-t] Show only supervisord log (-t follows)
scale <app> <proc>=<count> [<proc>=<count>] Scale an app via supervisord (use instead of ps:scale)
EOF
;;

Expand Down
75 changes: 75 additions & 0 deletions functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
tail_logs() {
[[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1
verify_app_name "$2"

local MODE="$1"
local APP="$2"
local FOLLOW=""
local LOGNAME="*.log"
local LOGFILES=""

if [ "$3" == "-t" ] && [ -n "$4" ]; then
FOLLOW="-f"
LOGNAME="${4}*.log"
elif [ "$3" == "-t" ]; then
FOLLOW="-f"
elif [ -n "$3" ]; then
LOGNAME="${3}*.log"
fi

local FINDQUERY=(-name "$LOGNAME")
if [ "$MODE" == "app" ]; then
FINDQUERY+=(! -name "supervisor.log")
fi

LOGFILES=$(find "/var/log/dokku/$APP" -type f \( "${FINDQUERY[@]}" \))

if [ -z "$LOGFILES" ]; then
echo "No log file matches \"$LOGNAME\""
exit 1
fi

tail -n 25 $FOLLOW $LOGFILES
}

function log_debug () {
if [ $DOKKU_TRACE ]; then
echo "$@"
fi
}

# Copies a file from the host into the container
function copy_to_container() {
local APP="$1"
local SOURCE_FILE="$2"
local TARGET_FILE="$3"
local IMAGE="dokku/$APP"

log_debug "Copying $SOURCE_FILE to container: $TARGET_FILE"

if [ ! -f "$SOURCE_FILE" ]; then
echo "Source file does not exist on host: $SOURCE_FILE"
exit 1
fi

local ACCESS_PERM=$(stat -c %a "$SOURCE_FILE")
local id=$(cat "$SOURCE_FILE" | \
docker run -i -a stdin $IMAGE \
/bin/bash -c "cat > '$TARGET_FILE' && chmod $ACCESS_PERM '$TARGET_FILE'")

test $(docker wait $id) -eq 0
docker commit $id $IMAGE > /dev/null
}

# Execute a command in the container and commit the resulting image
function run_in_container() {
local APP="$1"
local COMMAND="$2"
local IMAGE="dokku/$APP"

log_debug "Executing command in container: $COMMAND"
local id=$(docker run -i -a stdin $IMAGE /bin/bash -c "$COMMAND")

test $(docker wait $id) -eq 0
docker commit $id $IMAGE > /dev/null
}
34 changes: 0 additions & 34 deletions lib/helpers

This file was deleted.

18 changes: 9 additions & 9 deletions lib/procfile-to-supervisord
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function log_debug() {
}

function gen_supervisor_conf () {
cat << EOF
cat << EOF
[supervisord]
logfile=/var/log/app/supervisor.log
loglevel=info
Expand All @@ -32,15 +32,15 @@ EOF
}

function gen_supervisor_proc_conf () {
NAME="$1"
COMMAND="$2"
NUM_PROCS="$3"
PROCESS_NAME='%(program_name)s'
if [ "$NUM_PROCS" -gt 1 ]; then
PROCESS_NAME='%(program_name)s.%(process_num)02d'
fi
NAME="$1"
COMMAND="$2"
NUM_PROCS="$3"
PROCESS_NAME='%(program_name)s'
if [ "$NUM_PROCS" -gt 1 ]; then
PROCESS_NAME='%(program_name)s.%(process_num)02d'
fi

cat << EOF
cat << EOF
[program:${NAME}]
command=/exec ${COMMAND}
process_name:${PROCESS_NAME}
Expand Down
26 changes: 15 additions & 11 deletions post-release
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,36 @@ IMAGE="dokku/$1"
SCALE_FILE="$DOKKU_ROOT/$APP/SCALE"

PLUGIN_DIR=$(dirname $0)
. "$PLUGIN_DIR/lib/helpers"
source "$PLUGIN_DIR/functions"

# Check for Procfile
id=$(docker run -d $IMAGE test -f app/Procfile)
if [ $(docker wait $id) -ne 0 ]; then
exit 0
fi

copy_to_container "$PLUGIN_DIR/lib/procfile-to-supervisord" /usr/local/bin/procfile-to-supervisord
if [ -f "$SCALE_FILE" ]; then
echo "Found SCALE file: $SCALE_FILE"
copy_to_container "$SCALE_FILE" /app/SCALE
fi
copy_to_container "$APP" "$PLUGIN_DIR/lib/procfile-to-supervisord" \
/usr/local/bin/procfile-to-supervisord

echo "-----> Injecting Logging Supervisor ..."

if [ -f "$SCALE_FILE" ]; then
echo " Found SCALE file: $SCALE_FILE"
copy_to_container "$APP" "$SCALE_FILE" /app/SCALE
fi

if docker run -a stdout -i $IMAGE /usr/bin/dpkg -s supervisor > /dev/null; then
echo "supervisor is already installed (skipping apt-get update/install)"
echo " supervisor is already installed (skipping apt-get update/install)"
else
echo "supervisor is not installed (will install via apt-get)"
run_in_container "apt-get update && apt-get install -y supervisor && apt-get clean"
echo " supervisor is not installed (will install via apt-get)"
run_in_container "$APP" \
"apt-get update && apt-get install -y supervisor && apt-get clean"
fi

# Unlink /exec from /start
# Original builstep uses `ln -nsf /start /exec` that forks supervisor repeatedly
run_in_container "if [[ -L /exec ]];then rm -f /exec && cp -f /start /exec; fi"
run_in_container "$APP" \
"if [[ -L /exec ]];then rm -f /exec && cp -f /start /exec; fi"

# Replace /start with our custom start program:
copy_to_container "$PLUGIN_DIR/lib/start" /start
copy_to_container "$APP" "$PLUGIN_DIR/lib/start" /start