Из вывода моего скрипта я хочу захватить ВСЕ данные журналов с сообщениями об ошибках и перенаправить их все в файл журнала.
У меня есть сценарий, как показано ниже:
#!/bin/bash
(
echo " `date` : part 1 - start "
ssh -f admin@server.com 'bash /www/htdocs/server.com/scripts/part1.sh logout exit'
echo " `date` : sleep 120"
sleep 120
echo " `date` : part 2 - start"
ssh admin@server.com 'bash /www/htdocs/server.com/scripts/part2.sh logout exit'
echo " `date` : part 3 - start"
ssh admin@server.com 'bash /www/htdocs/server.com/scripts/part3.sh logout exit'
echo " `date` : END"
) | tee -a /home/scripts/cron/logs
Я хочу видеть все действия в файле /home/scripts/cron/logs
Но я вижу только то, что поставил после echo
команда.
Как проверить в журналах, что SSH
команда прошла успешно?
Мне нужно собрать все журналы. Мне это нужно, чтобы отслеживать результат каждой команды в моем скрипте, чтобы лучше анализировать, что происходит, когда скрипт не работает.
Обычно я помещаю что-то похожее на следующее в начале каждого скрипта (особенно если он будет работать как демон):
#!/bin/bash
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>log.out 2>&1
# Everything below will go to the file 'log.out':
Пояснение:
exec 3>&1 4>&2
Сохраняет файловые дескрипторы, чтобы их можно было восстановить в том виде, в котором они были до перенаправления, или использовать самих себя для вывода в те файлы, которые были до следующего перенаправления.
trap 'exec 2>&4 1>&3' 0 1 2 3
Восстановить файловые дескрипторы для определенных сигналов. Обычно не требуется, так как они должны быть восстановлены при выходе из суб-оболочки.
exec 1>log.out 2>&1
Перенаправить stdout
подавать log.out
затем перенаправить stderr
к stdout
. Обратите внимание, что порядок важен, если вы хотите, чтобы они обращались к одному и тому же файлу. stdout
должен быть перенаправленным раньше stderr
перенаправлен на stdout
.
С этого момента, чтобы увидеть вывод на консоли (возможно), вы можете просто перенаправить на &3
. Например,
echo "$(date) : part 1 - start" >&3
пойдет куда угодно stdout
был направлен, предположительно, консоли, до выполнения строки 3 выше.
чтобы получить вывод ssh в файл журнала, вы должны перенаправить stderr
к stdout
. вы можете сделать это, добавив 2>&1
после вашего сценария bash.
это должно выглядеть так:
#!/bin/bash
(
...
) 2>&1 | tee ...
если это не отображает сообщения в правильном порядке, попробуйте добавить другую подоболочку:
#!/bin/bash
((
...
) 2>&1) | tee ...
Когда я читаю ваш вопрос, вы не хотите регистрировать вывод, но вся последовательность команд, и в этом случае другие ответы вам не помогут.
Вызов сценариев оболочки с -x для вывода всего:
sh -x foo.sh
Войдите в нужный файл с помощью:
sh -x foo.sh >> /home/scripts/cron/logs
В bash вы можете поставить set -x
и после этого он распечатает каждую команду, которую он выполняет (и переменные bash). Вы можете выключить его с помощью set +x
.
Если вы хотите быть параноиком, вы можете поставить set -o errexit
в вашем сценарии. Это означает, что сценарий завершится ошибкой и остановится, если одна команда вернула ненулевой код выхода, что является стандартным способом unix для сигнализации о том, что что-то пошло не так.
Если вы хотите получить более качественные журналы, вам следует взглянуть на ts
в moreutils
пакет debian / ubuntu. Он добавит к каждой строке отметку времени и распечатает ее. Так вы можете видеть, когда что-то происходило.
Следуя тому, что говорили другие, набор руководство хороший ресурс. Я кладу:
#!/usr/bin/env bash
exec 1> command.log 2>&1
set -x
В верхней части скриптов я хочу продолжить, или set -ex
если он должен выйти из-за ошибки.
Я обнаружил, что @nicerobot (Как я могу полностью регистрировать все действия сценариев bash? ) ответа может быть недостаточно, чтобы полностью перенаправить весь вывод на консоль. Некоторые выходные данные все еще могут быть потеряны.
Полное перенаправление выглядит так:
#!/bin/bash
# some basic initialization steps including `NEST_LVL` and `SCRIPTS_LOGS_ROOT variables...
source ".../__myinit__.sh"
# no local logging if nested call
(( ! IMPL_MODE && ! NEST_LVL )) && {
export IMPL_MODE=1
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' EXIT HUP INT QUIT RETURN
[[ ! -e "${SCRIPTS_LOGS_ROOT}/.log" ]] && mkdir "${SCRIPTS_LOGS_ROOT}/.log"
# RANDOM instead of milliseconds
case $BASH_VERSION in
# < 4.2
[123].* | 4.[01] | 4.0* | 4.1[^0-9]*)
LOG_FILE_NAME_SUFFIX=$(date "+%Y'%m'%d_%H'%M'%S''")$(( RANDOM % 1000 ))
;;
# >= 4.2
*)
printf -v LOG_FILE_NAME_SUFFIX "%(%Y'%m'%d_%H'%M'%S'')T$(( RANDOM % 1000 ))" -1
;;
esac
(
(
myfoo1
#...
myfooN
# self script reentrance...
exec $0 "$@"
) | tee -a "${SCRIPTS_LOGS_ROOT}/.log/${LOG_FILE_NAME_SUFFIX}.myscript.log" 2>&1
) 1>&3 2>&4
exit $?
}
(( NEST_LVL++ ))
# usual script body goes here...
Объяснение:
echo
вызывает как консоль, так и файл, поэтому труба плюс тройник - единственный способ разделить выходной поток.(...)
для перенаправления каждого потока в отдельный файл или для восстановления всех потоков обратно в исходное состояние отдельными шагами. Вторая причина, потому что myfoo
вызовы перед повторным входом должны работать как есть, без дополнительного перенаправления.NEST_LVL
переменная для указания уровня вызова гнезда.IMPL_MODE
переменная.TL; DR - Вчера я написал набор инструментов для регистрации запусков и сессий программ.
В настоящее время доступно на https://github.com/wwalker/quick-log
Как администратор, я всегда хочу регистрировать вывод какой-либо команды, часто не сценария. Чтобы решить эту проблему, я написал несколько вещей. Самый простой - использовать программу "скрипт", как упомянуто xX0v0Xx. Я обнаружил, что вызов скрипта (без каких-либо аргументов) часто приводит к перезаписи вывода предыдущего скрипта. Итак, я создал этот псевдоним. Все, что он делает, это предотвращает перезапись. Вам нужен каталог ~ / tmp.
$ alias scr='script ~/tmp/typescript-$(date +%FT%T)'
$ scr
Script started, file is /home/wwalker/tmp/typescript-2019-12-05T18:56:31
$
Это здорово, когда я хочу поймать интерактивный сеанс.
Когда я хочу зарегистрировать вывод команды (скрипт или двоичный файл), мне нужен либо точный вывод, либо вывод с отметками времени перед каждой строкой. Итак, я написал эти две функции bash:
alias iso8601="date +%Y-%m-%dT%H:%M:%S"
justlog(){
name=$(basename "$1")
log=~/logs/${name}-$(iso8601)
"$@" > "$log" 2>&1
}
timelog(){
name=$(basename "$1")
log=~/logs/${name}-$(iso8601)
# https://github.com/wwalker/ilts
# You could replace ilts with ts
# /usr/bin/ts %FT%H:%M:%.S
"$@" |& ilts -S -E > "$log" 2>&1
}
Просто запустите свою команду, как обычно:
justlog run rcn rcn-work\\\\\* 'ps -ef -o lstart,cmd | grep [s]upervisor'
или
timelog run rcn rcn-work\\\\\* 'ps -ef -o lstart,cmd | grep [s]upervisor'
Это только что создало 2 файла с именем:
wwalker@polonium:~ ✓ $ ls -l ~/logs/run*
-rw-r--r-- 1 wwalker wwalker 10495 2019-12-05 18:21:14.985 /home/wwalker/logs/run-2019-12-05T18:21:13
-rw-r--r-- 1 wwalker wwalker 1694 2019-12-05 18:24:02.878 /home/wwalker/logs/run-2019-12-05T18:24:01
-rw-r--r-- 1 wwalker wwalker 7623 2019-12-05 18:25:07.873 /home/wwalker/logs/run-2019-12-05T18:25:06
-rw-r--r-- 1 wwalker wwalker 10296 2019-12-05 18:34:59.546 /home/wwalker/logs/run-2019-12-05T18:34:57
Но подождите, это еще не все !!
Я не хотел выполнять команду ls, чтобы найти имя файла журнала, который только что создал для меня justlog или timelog. Итак, я добавил еще 3 функции:
newestlog(){
name=$(basename "$1")
ls ~/logs/"${name}"* | tail -1
}
viewlog(){
name=$(basename "$1")
view $( newestlog "$name" )
}
lesslog(){
name=$(basename "$1")
less $( newestlog "$name" )
}
Итак, вы запускаете свою команду с помощью justlog (или timelog), а затем просто используете lesslog или viewlog (я, вероятно, создам журнал emacs для этих людей):
justlog run rcn rcn-work\\\\\* 'ps -ef -o lstart,cmd | grep [s]upervisor'
lesslog run
Все, нет ls ~/tmp
, нет игр с завершением вкладки, чтобы найти имя файла. Просто запустите lesslog (или viewlog, если вам нравится использовать vim для просмотра журналов).
Но ждать! Есть еще кое-что!
«Я все время использую grep в своих файлах журнала». Ответ, как вы уже догадались, greplog
Сначала получите текст из всех поврежденных файлов /etc/cron.d/atop сервера 800:
justlog fordcrun 'cat /etc/cron.d/atop; md5dum /etc/cron.d/atop'
Затем получите имена хостов (в строке над выводом в файле :-)) с помощью greplog:
wwalker@polonium:~ ✓ $ greplog fordcrun -B1 -F "0 0 * * root"
int-salt-01:
0 0 * * root systemctl restart atop
--
rcn-pg-01:
0 0 * * root systemctl restart atop
rcn-pg-02:
0 0 * * root systemctl restart atop
rcn-pg-03:
0 0 * * root systemctl restart atop
Вы можете просто использовать «скрипт».
man script
для подробностей.
Пример:
script -a -e -c "set -x; echo this is logging ..; <your script can be called here>" mylogfile.log