Как я могу подключиться к печати Perl?
======================================

Вот сценарий. У вас есть большое количество устаревших сценариев, и все они используют общую библиотеку. Указанные сценарии используют оператор print для диагностического вывода. Никакие изменения не допускаются в сценариях - они распространяются повсеместно, имеют свои одобрения и уже давно оставили плодотворные долины надзора и контроля.

Теперь пришла новая потребность: регистрация должна быть добавлена в библиотеку. Это должно быть сделано автоматически и прозрачно, без необходимости изменения скриптов пользователями стандартной библиотеки. К обычным библиотечным методам можно просто добавить журналы вызовов; это легкая часть. Сложность заключается в том, что диагностический вывод этих сценариев всегда отображался с использованием оператора print. Этот диагностический вывод должен быть сохранен, но, что не менее важно, обработан.

В качестве примера такой обработки библиотека должна записывать только напечатанные строки, содержащие слова «предупреждение», «ошибка», «уведомление» или «внимание». Приведенный ниже чрезвычайно простой и надуманный пример кода (tm) будет записывать некоторые из указанных выходных данных:

(Я бы хотел избежать таких проблем, как «что на самом деле должно быть зарегистрировано», «печать не должна использоваться для диагностики», «perl sucks» или «в этом примере есть недостатки xy и z» ... это значительно упрощено для краткости и ясности.)

Основная проблема сводится к захвату и обработке данных, переданных на печать (или любой другой встроенный perl, в соответствии с этими соображениями). Является ли это возможным? Есть ли способ сделать это чисто? Существуют ли какие-либо модули журналирования, которые имеют зацепки, чтобы позволить вам это сделать? Или это что-то, чего следует избегать, как чумы, и я должен отказаться от того, чтобы когда-либо захватывать и обрабатывать печатную продукцию?

Дополнительно: Это должно работать кроссплатформенно - Windows и * nix одинаково. Процесс запуска сценариев должен оставаться таким же, как и вывод из сценария.

Дополнительный дополнительный: интересное предложение, сделанное в комментариях ответа codelogic:

Вы можете подкласс[http://perldoc.perl.org/IO/Handle.html](https://perldoc.perl.org/IO/Handle.html) и создайте свой собственный дескриптор файла, который будет выполнять регистрацию. - Камил Кисиэль

Это может сделать это с двумя оговорками:

1) Мне нужен способ экспортировать эту функциональность любому, кто использует общую библиотеку. Это должно автоматически применяться к STDOUT и, вероятно, к STDERR.

2)[IO :: Ручка](https://perldoc.perl.org/IO/Handle.html) Документация гласит, что вы не можете создать подкласс, и мои попытки до сих пор были бесплодными. Есть ли что-то особенное, что нужно для создания подклассов IO :: Handle? Стандартный «use base» IO :: Handle и последующее переопределение методов new / print, похоже, ничего не делают.

Окончательное редактирование: похоже, IO :: Handle - тупик, но Tie :: Handle может это сделать. Спасибо за все предложения; они все действительно хороши. Я собираюсь попробовать маршрут Tie :: Handle. Если это вызовет проблемы, я вернусь!

Приложение: Обратите внимание, что немного поработав с этим, я обнаружил, что Tie :: Handle будет работать, если вы не сделаете ничего хитрого. Если вы используете какие-либо функции IO :: Handle с вашими связанными STDOUT или STDERR, то, по сути, это чушь, чтобы они работали надежно - я не смог найти способ заставить метод autoflush IO :: Handle работать с моими связанными справиться. Если бы я включил автозапуск до того, как связал ручку, это сработало бы. Если это работает для вас, маршрут Tie :: Handle может быть приемлемым.

Существует ряд встроенных модулей, которые вы можете переопределить (см.[perlsub](https://perldoc.perl.org/perlsub.html#Overriding-Built-in-Functions)). Тем не мение,`print` это одна из встроенных функций, которая не работает таким образом. Трудности преодоления`print` подробно на этом[нить перлмонка](http://www.perlmonks.org/?node=!Overriding%20Builtin%20print).

Тем не менее, выМожно

Создать пакетСвяжите ручкуВыберите эту ручку.Теперь пара человек дали базовую структуру, но она работает примерно так:

Вы можете переопределить`printf` таким же образом:

Увидеть[Tie :: Handle](http://search.cpan.org/perldoc?Tie::Handle) для чего все, что вы можете переопределить поведение STDOUT.



Много вариантов. Используйте select (), чтобы изменить дескриптор файла, для которого по умолчанию используется печать. Или связать STDOUT. Или снова откройте его. Или примените слой IO к этому.



Это не ответ на ваш вопрос, но вы должны быть в состоянии принять логику для собственного использования. Если нет, возможно, кто-то еще найдет это полезным.

Поймать искаженные заголовки, прежде чем они произойдут ...

использование:



Вы можете использовать Perl's[Выбрать](https://perldoc.perl.org/functions/select.html) перенаправить STDOUT.

Описатель файла может быть чем угодно, даже каналом для другого процесса, который публикует сообщения вашего журнала.

[PerlIO :: тройник](http://search.cpan.org/~gfuji/PerlIO-Util-0.60/lib/PerlIO/tee.pm) в[PerlIO :: Util](http://search.cpan.org/~gfuji/PerlIO-Util-0.60/) Модуль, кажется, позволяет вам «выводить» выходные данные дескриптора файла нескольким адресатам (например, процессор журналов и STDOUT).



Вы можете запустить скрипт из скрипта-обертки, который фиксирует стандартный вывод исходного скрипта и записывает результат где-то разумно.