سؤال

إليك سيناريو. لديك كمية كبيرة من البرامج النصية القديمة، وكلها باستخدام مكتبة مشتركة. قال البرامج النصية استخدم بيان "الطباعة" للإخراج التشخيصي. لا يسمح بإجراء تغييرات على البرامج النصية - وهي تتراوح بعيدة وعرضها، ولديها موافقتها، وقد غادرت منذ فترة طويلة من الوديان المثمرة للرقابة والسيطرة عليها.

الآن وصلت حاجة جديدة: يجب الآن إضافة التسجيل إلى المكتبة. يجب أن يتم ذلك تلقائيا وشفافا، دون وجود مستخدمين من المكتبة القياسية التي تحتاج إلى تغيير البرامج النصية الخاصة بهم. يمكن أن تحتوي أساليب المكتبة الشائعة ببساطة على المكالمات الإضافية؛ هذا هو الجزء السهل. الجزء الصعب يكمن في حقيقة أن الإخراج التشخيصي من هذه النصوص قد عرضت دائما باستخدام عبارة "الطباعة". يجب تخزين هذا الناتج التشخيصي، ولكن بنفس القدر، معالجتها.

كمثال على هذه المعالجة، يجب على المكتبة فقط تسجيل الأسطر المطبوعة التي تحتوي على الكلمات "تحذير"، "خطأ"، "لاحظ"، أو "الاهتمام". سيكون أدناه رمز مثال تافهة ومتعارض للغاية (TM) يسجل بعض الناتج المذكور:

sub CheckPrintOutput
{
    my @output = @_; # args passed to print eventually find their way here.
    foreach my $value (@output) {
         Log->log($value) if $value =~ /warning|error|notice|attention/i;
    }
}

(أرغب في تجنب مثل هذه المشكلات ك "ما يجب تسجيل الدخول بالفعل"، لا ينبغي أن تستخدم الطباعة للتشخيصات "،" Perl Sucks "، أو" هذا المثال يحتوي على العيوب XY و Z '... هذا هو مبسطة كبيرة للإيجاز والوضوح.)

المشكلة الأساسية تعود إلى التقاط ومعالجة البيانات التي تم تمريرها إلى طباعة (أو أي مدمج بيرل، على طول تلك الخطوط من التفكير). هل هو ممكن؟ هل هناك أي طريقة للقيام بذلك نظيفة؟ هل هناك أي وحدات تسجيل لها خطاف للسماح لك بذلك؟ أم أنها شيء يجب تجنبه مثل الطاعون، ويجب أن أتخلى عن التقاط وإخراج الإخراج المطبوع من أي وقت مضى؟

إضافي: يجب أن يعمل هذا عبر منصة - Windows و * Nix على حد سواء. يجب أن تظل عملية تشغيل البرامج النصية هي نفسها، كما يجب أن يكون الإخراج من البرنامج النصي.

إضافية إضافية: اقتراح مثير للاهتمام المحرز في تعليقات إجابة Codelogic:

يمكنك الفئة الفرعية http://perldoc.perl.org/io/handle.html. وإنشاء مؤشر الملفات الخاصة بك مما سيفعل عمل التسجيل. - كامل كيسيل

هذا قد يفعل ذلك، مع اثنين من التحذير:

1) أحتاج إلى طريقة لتصدير هذه الوظيفة لأي شخص يستخدم المكتبة المشتركة. يجب أن تنطبق تلقائيا على Stdout وربما stderr أيضا.

2) IO :: مقبض تقول الوثائق أنك لا تستطيع الفضو، ومحاولاتي حتى الآن كانت غير مثمرة. هل هناك أي شيء خاص مطلوب لصنع العمل IO :: التعامل؟ يبدو أن "استخدام قاعدة" القياسية IO :: المقبض "ثم تجاوز طرق / الطباعة الجديدة لا تفعل شيئا.

تحرير النهائي: يبدو وكأنه IO :: مقبض هو نهاية مسدود، ولكن التعادل :: مقبض قد تفعل ذلك. شكرا لجميع الاقتراحات؛ انهم جميعا جيدة حقا. انا ذاهب لإعطاء التعادل :: التعامل مع الطريق المحاولة. إذا كان الأمر يسبب مشاكل سأعود!

إضافة: لاحظ أنه بعد العمل مع هذا قليلا، وجدت أن التعادل :: المقبض سيعمل، إذا كنت لا تفعل أي شيء صعبة. إذا كنت تستخدم أيا من ميزات IO :: مقبض مع Stdout المرتبط الخاص بك أو Stderr، فهذه الأساسا Crapshoot للحصول عليها يعمل بشكل موثوق - لم أتمكن من إيجاد طريقة للحصول على طريقة تلقائية ل io :: مقبض للعمل على مرتبط مقبض. إذا قمت بتمكين AutoFlush قبل ربط المقبض، فسوف تعمل. إذا كان ذلك يعمل من أجلك، فقد يكون الطريق التعادل :: مقبول.

هل كانت مفيدة؟

المحلول

هناك عدد من الأعمال المدمجة التي يمكنك تجاوزها (انظر perlsub.). ومع ذلك، print هي واحدة من الشركات المدمجة التي لا تعمل بهذه الطريقة. صعوبات الغالوبة print مفصلة في هذا موضوع بيرلمونك.

ولكن هل يمكن

  1. إنشاء حزمة
  2. ربط مقبض
  3. حدد هذا المقبض.

الآن، أعطى زوجان من الناس الإطار الأساسي، لكنه يعمل نوعا من مثل هذا:

package IO::Override;
use base qw<Tie::Handle>;
use Symbol qw<geniosym>;

sub TIEHANDLE { return bless geniosym, __PACKAGE__ }

sub PRINT { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    print $OLD_STDOUT join( '', 'NOTICE: ', @_ );
}

tie *PRINTOUT, 'IO::Override';
our $OLD_STDOUT = select( *PRINTOUT );

يمكنك تجاوز printf بنفس الاسلوب:

sub PRINTF { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    my $format = shift;
    print $OLD_STDOUT join( '', 'NOTICE: ', sprintf( $format, @_ ));
}

يرى التعادل :: مقبض لماذا كل ما يمكنك تجاوز سلوك Stdout.

نصائح أخرى

يمكنك استخدام بيرل تحديد لإعادة توجيه stdout.

open my $fh, ">log.txt";
print "test1\n";
my $current_fh = select $fh;
print "test2\n";
select $current_fh;
print "test3\n";

قد يكون مؤشر الملفات أي شيء، حتى أنابيب لعملية أخرى تقوم بمعالجة رسائل السجل الخاصة بك.

بيرليو :: تي في ال Perlio :: Util. يبدو أن الوحدة النمطية تتيح لك "إخراج" إخراج مقبض ملف إلى وجهات متعددة (مثل معالج السجل و Stdout).

الكثير من الخيارات. استخدم SELECT () لتغيير filehandle التي تطبع الإعدادات الافتراضية إليها. أو ربط stdout. أو إعادة فتحه. أو تطبيق طبقة io لذلك.

هذه ليست هي الحل على مشكلتك ولكن يجب أن تكون قادرا على تبني المنطق لاستخدامك الخاص. إذا لم يكن كذلك، فربما يجد شخص آخر مفيدا.

اصطياد رؤوس مشوهة قبل أن تحدث ...

package PsychicSTDOUT;
use strict;

my $c = 0;
my $malformed_header = 0;
open(TRUE_STDOUT, '>', '/dev/stdout');
tie *STDOUT, __PACKAGE__, (*STDOUT);

sub TIEHANDLE {
    my $class = shift;
    my $handles = [@_];
    bless $handles, $class;
    return $handles;
}

sub PRINT {
    my $class = shift;
    if (!$c++ && @_[0] !~ /^content-type/i) {
        my (undef, $file, $line) = caller;
        print STDERR "Missing content-type in $file at line $line!!\n";
        $malformed_header = 1;
    }
    return 0 if ($malformed_header);
    return print TRUE_STDOUT @_;
}
1;

الاستعمال:

use PsychicSTDOUT;
print "content-type: text/html\n\n"; #try commenting out this line
print "<html>\n";
print "</html>\n";

يمكنك تشغيل البرنامج النصي من برنامج نصي Wrapper الذي يلتقط Stdout Script الأصلي ويكتب الإخراج معقولا في مكان ما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top