diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 87c9d6feb4a..c8b6edb7d1e 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -2316,6 +2316,25 @@ DOKKU_SCHEDULER="$1"; APP="$2"; FORMAT="$3"; # TODO ``` +### `scheduler-run-logs` + +> Warning: The scheduler plugin trigger apis are under development and may change +> between minor releases until the 1.0 release. + +- Description: Allows you to run scheduler commands when retrieving one-off container logs +- Invoked by: `dokku run` +- Arguments: `$DOKKU_SCHEDULER $APP $CONTAINER $TAIL $PRETTY_PRINT $NUM` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +DOKKU_SCHEDULER="$1"; APP="$2"; CONTAINER="$3"; TAIL="$4"; PRETTY_PRINT="$5"; NUM="$6" + +# TODO +``` + ### `scheduler-stop` > Warning: The scheduler plugin trigger apis are under development and may change diff --git a/docs/processes/one-off-tasks.md b/docs/processes/one-off-tasks.md index f6234379891..ae4d39ec8a0 100644 --- a/docs/processes/one-off-tasks.md +++ b/docs/processes/one-off-tasks.md @@ -1,10 +1,11 @@ # One-off Tasks ``` -run [-e|--env KEY=VALUE] [--no-tty] # Run a command in a new container using the current app image -run:detached [-e|-env KEY=VALUE] [--no-tty] # Run a command in a new detached container using the current app image -run:list [--format json|stdout] [] # List all run containers for an app -run:stop # Stops all run containers for an app or a specified run container +run [-e|--env KEY=VALUE] [--no-tty] # Run a command in a new container using the current app image +run:detached [-e|-env KEY=VALUE] [--no-tty] # Run a command in a new detached container using the current app image +run:list [--format json|stdout] [] # List all run containers for an app +run:logs [-h] [-t] [-n num] [-q] # Display recent log output for run containers +run:stop # Stops all run containers for an app or a specified run container ``` Sometimes it is necessary to run a one-off command under an app. Dokku makes it easy to run a fresh container via the `run` command. @@ -69,6 +70,35 @@ dokku run:detached node-js-app ls -lah # returns the ID of the new container ``` +### Displaying one-off container logs + +You can easily get logs of all one-off containers for an app using the `logs` command: + +```shell +dokku run:logs node-js-app +``` + +Logs are pulled via integration with the scheduler for the specified application via "live tailing". As such, logs from previously running deployments are usually not available. Users that desire to see logs from previous deployments for debugging purposes should persist those logs to external services. Please see Dokku's [vector integration](/docs/deployment/logs.md#vector-logging-shipping) for more information on how to persist logs across deployments to ship logs to another service or a third-party platform. + +#### Behavioral modifiers + +Dokku also supports certain command-line arguments that augment the `run:log` command's behavior. + +``` +--container NAME # the name of a specific container to show logs for +-n, --num NUM # the number of lines to display +-t, --tail # continually stream logs +-q, --quiet # display raw logs without colors, time and names +``` + +You can use these modifiers as follows: + +```shell +dokku run:logs -t --container node-js-app.run.1234 +``` + +The above command will show logs continually from the `node-js-app.run.1234` one-off run process. + ### Listing one-off containers > New as of 0.25.0 diff --git a/plugins/run/help-functions b/plugins/run/help-functions index 28f77b627e6..ec2835771d2 100755 --- a/plugins/run/help-functions +++ b/plugins/run/help-functions @@ -30,6 +30,7 @@ fn-help-content() { run [-e|--env KEY=VALUE] [--no-tty] , Run a command in a new container using the current app image run:detached [-e|-env KEY=VALUE] [--no-tty] , Run a command in a new detached container using the current app image run:list [--format json|stdout] , List all run containers for an app + run:logs [-h] [-t] [-n num] [-q], Display recent log output for run containers run:stop , Stops all run containers for an app or a specified run container help_content } diff --git a/plugins/run/internal-functions b/plugins/run/internal-functions index 0502cfaa7a7..13ce0cb20ae 100755 --- a/plugins/run/internal-functions +++ b/plugins/run/internal-functions @@ -110,6 +110,71 @@ cmd-run-list() { plugn trigger scheduler-run-list "$DOKKU_SCHEDULER" "$APP" "$FORMAT" } +cmd-run-logs() { + declare desc="display recent log output" + declare cmd="run:logs" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="" + + local CONTAINER_NAME="" NUM="100" PRETTY_PRINT=false TAIL=false + while [[ $# -gt 0 ]]; do + case "$1" in + --container=*) + local arg=$(printf "%s" "$1" | sed -E 's/(^--container=)//g') + CONTAINER_NAME="$arg" + shift + ;; + --container) + if [[ ! $2 ]]; then + dokku_log_warn "expected $1 to have an argument" + break + fi + CONTAINER_NAME="$2" + shift 2 + ;; + -n | --num) + local NUM="$2" + shift 2 + ;; + -q | --quiet) + local PRETTY_PRINT=true + shift + ;; + -t | --tail) + local TAIL=true + shift + ;; + *) + APP="$1" + shift + ;; + esac + done + + if [[ -z "$APP" ]] && [[ -z "$CONTAINER_NAME" ]]; then + dokku_log_fail "No container or app specified" + fi + + if [[ -n "$CONTAINER_NAME" ]]; then + if [[ "$(echo "$CONTAINER_NAME" | grep -o '\.' | wc -l)" -ne 2 ]]; then + dokku_log_fail "Invalid container name specified: $CONTAINER_NAME" + fi + + if [[ -n "$APP" ]] && [[ "$APP" != "$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" ]]; then + dokku_log_fail "Specified app does not app in container name" + fi + + APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)" + if [[ "$(echo "$CONTAINER_NAME" | cut -d'.' -f2)" != "run" ]]; then + dokku_log_fail "Specified container must be a run container" + fi + fi + + verify_app_name "$APP" + DOKKU_SCHEDULER=$(get_app_scheduler "$APP") + plugn trigger scheduler-run-logs "$DOKKU_SCHEDULER" "$APP" "$CONTAINER_NAME" "$TAIL" "$PRETTY_PRINT" "$NUM" +} + cmd-run-stop() { declare desc="Stops all run containers for an app or a specified run container" declare cmd="run:stop" diff --git a/plugins/run/subcommands/logs b/plugins/run/subcommands/logs new file mode 100755 index 00000000000..ee745ecff56 --- /dev/null +++ b/plugins/run/subcommands/logs @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -eo pipefail +source "$PLUGIN_AVAILABLE_PATH/run/internal-functions" +[[ $DOKKU_TRACE ]] && set -x + +cmd-run-logs "$@" diff --git a/plugins/scheduler-docker-local/scheduler-run-logs b/plugins/scheduler-docker-local/scheduler-run-logs new file mode 100755 index 00000000000..22d58a2254f --- /dev/null +++ b/plugins/scheduler-docker-local/scheduler-run-logs @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +trigger-scheduler-docker-local-scheduler-logs() { + declare desc="scheduler-docker-local scheduler-logs plugin trigger" + declare trigger="scheduler-logs" + declare DOKKU_SCHEDULER="$1" APP="$2" CONTAINER_NAME="$3" TAIL="$4" PRETTY_PRINT="$5" NUM="$6" + local DOKKU_LOGS_ARGS="" + + if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then + return + fi + + if [[ "$TAIL" == "true" ]]; then + DOKKU_LOGS_ARGS="--follow " + fi + + local COLORS=(36 33 32 35 31) + + if [[ -n "$CONTAINER_NAME" ]]; then + local CONTAINERS=("$CONTAINER_NAME") + else + local CONTAINERS=() + NAMES="$("$DOCKER_BIN" container ls --all --filter "label=com.dokku.app-name=$APP" --filter "label=com.dokku.container-type=run" --format '{{ .Names }}')" + while IFS= read -r CONTAINER_NAME; do + CONTAINERS+=("$CONTAINER_NAME") + done <<<"$NAMES" + fi + + local DOKKU_LOGS_ARGS+="--tail $NUM" + ((MAX_INDEX = ${#CONTAINERS[*]} - 1)) || true + for i in ${!CONTAINERS[*]}; do + local DYNO="$(echo "${CONTAINERS[i]}" | cut -d. -f3)" + local CID="${CONTAINERS[i]}" + local COLOR=${COLORS[i % ${#COLORS[*]}]} + if [[ $PRETTY_PRINT == "true" ]]; then + local DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)" + else + local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'" + local DOKKU_LOGS_CMD+="($DOCKER_BIN logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)" + fi + if [[ $i != "$MAX_INDEX" ]]; then + local DOKKU_LOGS_CMD+="& " + else + local DOKKU_LOGS_CMD+="; " + fi + done + bash -c "($DOKKU_LOGS_CMD)" +} + +trigger-scheduler-docker-local-scheduler-logs "$@"