2010-06-10 4 views
8

Gibt es eine Möglichkeit Log::Log4perl zu verwenden, um ein intelligentes Modul zur Selbstaufzeichnung zu erstellen, das seine Operationen auch dann protokolliert, wenn das aufrufende Skript Log4perl nicht initialisiert? Soweit ich das anhand der Dokumentation feststellen kann, besteht die einzige Möglichkeit zur Verwendung von Log4perl darin, es im laufenden Skript von einer Konfiguration aus zu initialisieren. Dann protokollieren Module, die Log4perl-Aufrufe implementieren, sich selbst anhand der Log4perl-Konfiguration des Aufrufers.Erstellen von Self-Logging-Modulen mit Log :: Log4perl

Stattdessen würde ich die Module wie eine Standard-Initialisierung Config für Log4perl bereitzustellen. Dies würde den Standard-Dateiappender für die Modulkategorie bereitstellen. Dann könnte ich dieses Verhalten außer Kraft setzen, indem ich Log4perl im Aufrufer mit einer anderen Konfiguration bei Bedarf einsetze, und alles würde hoffentlich funktionieren.

Ist diese Art der defensiven Protokollierungsverhalten möglich, oder bin ich brauche auf dem Gehen verlassen Initing Log4perl in jedem .pl-Skript, das das Modul ruft ich angemeldet wollen?

Antwort

7

Ich tue dies in einer benutzerdefinierten Log Rolle in Moose (irrelevant komplizierten Code entfernt):

package MyApp::Role::Log; 

use Moose::Role; 
use Log::Log4perl; 

my @methods = qw(
    log trace debug info warn error fatal 
    is_trace is_debug is_info is_warn is_error is_fatal 
    logexit logwarn error_warn logdie error_die 
    logcarp logcluck logcroak logconfess 
); 

has _logger => (
    is => 'ro', 
    isa => 'Log::Log4perl::Logger', 
    lazy_build => 1, 
    handles => \@methods, 
); 

around $_ => sub { 
    my $orig = shift; 
    my $this = shift; 

    # one level for this method itself 
    # two levels for Class:;MOP::Method::Wrapped (the "around" wrapper) 
    # one level for Moose::Meta::Method::Delegation (the "handles" wrapper) 
    local $Log::Log4perl::caller_depth; 
    $Log::Log4perl::caller_depth += 4; 

    my $return = $this->$orig(@_); 

    $Log::Log4perl::caller_depth -= 4; 
    return $return; 

} foreach @methods; 

method _build__logger => sub { 
    my $this = shift; 

    my $loggerName = ref($this); 
    Log::Log4perl->easy_init() if not Log::Log4perl::initialized(); 
    return Log::Log4perl->get_logger($loggerName) 
}; 

Wie Sie sehen können, wird das Protokoll Objekt selbst Initialisierung - wenn Log::Log4perl->init nicht aufgerufen wurde, dann easy_init heißt. Sie können dies leicht ändern, damit jedes Modul seinen Logger anpassen kann - ich tue dies mit optionalen Rollenparametern, mit ref($this) als Standardfallback.

PS. Vielleicht möchten Sie auch auf MooseX::Log::Log4perl schauen, wo ich angefangen habe, bevor ich die Rolle der Logger oben verwendet habe. Irgendwann, wenn ich dazu komme, werde ich einige dringend benötigte Patches an dieses MX-Modul senden, um einige Funktionen hinzuzufügen, die ich hinzugefügt habe.

+1

, werden diese Moose Objekte werden Protokollierung, so sieht es aus wie es einfach genug sein werden, um loslegen. Vielen Dank! – Oesor

+0

@Oesor: hurra, Elch FTW! :) – Ether

+0

kann ich fragen, was ein MX-Modul ist? Ich kenne PP und XS, ist MX eine Abkürzung für Moose? – DVK

1

Die kurze Antwort ist Log :: Log4perl :: initialisiert() zu nennen; irgendwann und wenn es falsch ist, richten Sie eine Standardprotokollierung ein.

Der schwierige Teil ist „irgendwann.“

Sie können es BEGIN nicht in {}, weil dann dem Hauptskript Ihre Initialisierung stampfen wird, obwohl Sie unnessary Dateien erstellt. Sie möchten es nicht vor jedem Aufruf von get_logger() tun, weil das verschwenderisch ist. Also sollten Sie es während der Initialisierung des Moduls tun, sagen wir sub neu oder sub init. Zum Glück

Verwandte Themen