У меня есть программа, вывод которой я перенаправить в файл журнала:
./my_app > log
Я хотел бы очистить (то есть пустой) время от времени (по запросу) и пробовал различные вещи, как
cat "" > log
Однако всегда кажется, что исходный канал затем нарушается, и программа больше не перенаправляет свой вывод в файл журнала.
Есть ли способ сделать это?
Обновить
Обратите внимание, что я не могу изменить приложение, производящее вывод. Он просто выплевывает его на стандартный вывод, и я хочу сохранить его в журнале, чтобы я мог проверить его, когда мне это нужно, и очистить его, когда захочу. Однако мне не нужно перезапускать приложение.
bash
io-redirection
bangnab
источник
источник
syslogd
илиlogrotate
./my_app >> log
(чтобы принудительно добавить) иcp /dev/null log
обрезать это?cat "" > log
недопустимаяcat
команда, так как файл не вызывается""
.Ответы:
Другая форма этой проблемы возникает с долго работающими приложениями, журналы которых периодически меняются. Даже если вы переместите исходный журнал (например,
mv log.txt log.1
) и немедленно замените его файлом с тем же именем до того, как произойдет какое-либо фактическое ведение журнала, если процесс удерживает файл открытым, он либо завершит записьlog.1
(потому что это все еще может быть открытый индекс) или ни к чему.Распространенный способ справиться с этим (сам системный регистратор работает таким образом) - внедрить обработчик сигналов в процессе, который закроет и снова откроет свои журналы. Затем, когда вы захотите переместить или очистить (удалив) журнал, сразу же отправьте этот сигнал процессу.
Вот простая демонстрация bash - простите мои грубые навыки оболочки (но если вы собираетесь редактировать это для лучших практик и т. Д., Пожалуйста, убедитесь, что вы сначала понимаете функциональность и протестируете свою ревизию перед редактированием):
Начните это с разветвления на задний план:
Обратите внимание, что он сообщает свой PID в терминал, а затем начинает входить в систему
log.txt
. Теперь у вас есть 2 минуты, чтобы поиграть. Подождите несколько секунд и попробуйте:Просто
kill -2 12356
у вас тоже может получиться. Сигнал 2 - SIGINT (это также то, что делает Ctrl-C, так что вы можете попробовать это на переднем плане и переместить или удалить файл журнала из другого терминала), которыйtrap
должен перехватить. Проверять;Теперь давайте посмотрим, записывает ли он все
log.txt
еще, хотя мы переместили его:Обратите внимание, что он продолжал идти прямо туда, где остановился. Если вы не хотите сохранять запись, просто очистите журнал, удалив его
Проверьте:
Продолжается.
Вы не можете сделать это в сценарии оболочки для исполняемого подпроцесса, к сожалению, потому что, если он находится на переднем плане, собственные обработчики сигналов bash
trap
приостанавливаются, и если вы разветвляете его в фоновом режиме, вы не можете переназначить его выход. То есть это то, что вы должны реализовать в своем приложении.Тем не мение...
Если вы не можете изменить приложение (например, потому что вы его не написали), у меня есть утилита CLI, которую вы можете использовать в качестве посредника. Вы также можете реализовать простую версию этого в скрипте, который служит каналом для журнала:
Давайте назовем это
pipetrap.sh
. Теперь нам нужна отдельная программа для тестирования, имитирующая приложение, которое вы хотите зарегистрировать:Это будет
test.sh
:Это два отдельных процесса с отдельными PID. Чтобы очистить
test.sh
вывод, который проходит черезpipetrap.sh
:Проверьте:
15858,,
test.sh
все еще работает, и его выходные данные регистрируются. В этом случае никаких изменений в приложении не требуется.источник
TL; DR
Откройте файл журнала в режиме добавления :
Затем вы можете безопасно обрезать его:
Детали
В борновоподобной оболочке существует 3 основных способа открытия файла для записи. В режиме только для записи (
>
), чтение + запись (<>
) или добавление (и только запись>>
).В первых двух ядро запоминает текущую позицию, в которой вы (под вами, я имею в виду, описание открытого файла , разделяемое всеми дескрипторами файлов, которые продублировали или унаследовали его путем разветвления от того, на котором вы открыли файл), находитесь в файл.
Когда вы делаете:
log
открыт в режиме « только для записи» оболочкой для выводаcmd
.cmd
(его начальный процесс порожден оболочкой и всеми возможными дочерними элементами) при записи в их стандартный вывод записывать в текущей позиции курсора, содержащейся в открытом описании файла, которое они разделяют в этом файле.Например, при
cmd
первоначальной записиzzz
позиция будет иметь байтовое смещение 4 в файле, а в следующий разcmd
или когда его дочерние элементы будут записывать в файл, именно туда будут записываться данные независимо от того, вырос ли файл или сократился в интервале ,Если файл сжался, например, если он был усечен с
и
cmd
пишетxx
, теxx
будут записаны со смещением4
, и первые 3 символа будут заменены на NUL символов.Это означает, что вы не можете усечь файл, который был открыт в режиме только для записи (и то же самое для чтения + записи ), как если бы вы это делали, процессы, у которых в файле были открыты файловые дескрипторы, оставят NUL-символы в начале file (те, за исключением OS / X, обычно не занимают место на диске, хотя они становятся разреженными файлами).
Вместо этого (и вы заметите, что большинство приложений делают это, когда они пишут в файлы журналов), вы должны открыть файл в режиме добавления :
или
если вы хотите начать с пустого файла.
В режиме добавления все записи производятся в конце файла, независимо от того, где была последняя запись:
Также безопаснее, если два процесса по ошибке открыли (таким образом) файл (например, если вы запустили два экземпляра одного и того же демона), их выходные данные не будут перезаписывать друг друга.
В последних версиях Linux вы можете проверить текущую позицию и был ли дескриптор файла открыт в режиме добавления , посмотрев
/proc/<pid>/fdinfo/<fd>
:Или с:
Эти флаги соответствуют флагам O ..._, передаваемым
open
системному вызову.(
O_APPEND
0x400 или восьмеричное 02000)Так оболочечному
>>
открывает файл сO_WRONLY|O_APPEND
(и 0100000 здесь O_LARGEFILE , которая не имеет отношения к этому вопросу) в то время как>
этоO_WRONLY
только (и<>
этоO_RDWR
только).Если вы делаете:
для поиска файлов, открытых с помощью
O_APPEND
, вы найдете большинство файлов журналов, открытых на данный момент для записи в вашей системе.источник
:
(двоеточие) в: >
?:
. Без команды поведение меняется между оболочками.Если я правильно понимаю,
tee
кажется разумным подход:источник
В качестве быстрого решения вы можете использовать бревно с ротацией (например, ежедневная ротация):
и перенаправить логирование к нему
./my_app >> log$date.log
источник
Эта проблема давно решается с помощью системного журнала (во всех его вариантах), но есть два инструмента, которые решат вашу конкретную проблему с минимальными усилиями.
Первое, более портативное, но менее универсальное решение - это регистратор (необходим для всех инструментов администратора). Это простая утилита, которая копирует стандартный ввод в системный журнал. (обойдя проблему и сделав ротацию файлов проблемой logrotate и syslog)
Второе, более элегантное, но менее портативное решение - это syslog-ng, которое помимо приема сообщений журнала из стандартных сокетов syslog может выполнять программы, выходные данные которых фильтруются через регистратор. (Я еще не использовал эту функцию, но она выглядит идеально для того, что вы хотите сделать.)
источник