jellisii2 has asked for the wisdom of the Perl Monks concerning the following question:

I'm converting one of my existing programs to use Log4perl instead of the code that I wrote to make logging happen. I've hit on a snag that I can't quite wrap my head around currently.

In my program, I have a a Tkx textbox widget that I've been updating in my homebrew logging sub. This widget allows me to easily scroll through the messages when something bombs. I'd like to retain that functionality with a minimum of fuss.

I've been reading over the log4perl documentation, and while I see that I MIGHT be able to roll my own appender. Unfortunately, I'm not currently versed enough with the intricacies to do so. I may have to correct this to reach my goal, but before I embark on that journey, I'd like to ensure that there's some collective wisdom that says "yep, that's how you're going to have to do it."

I *could* potentially take the message and kick it to a subroutine for writing to the textbox, by capturing the return and submitting it, but that doesn't seem to be the most elegant way of handling this.

Thoughts?

Replies are listed 'Best First'.
Re: Log4perl and Tkx
by Anonymous Monk on Nov 24, 2011 at 00:43 UTC

    Yeah, Log::Log4perl::Appender::String isn't quite right for the job, and text widget doesn't support -textvariable

    Here is a start, run with it :)

    use strict; use warnings; use Tkx; use Log::Log4perl; Main( @ARGV ); exit( 0 ); sub Main { $Tkx::TRACE=64; Tkx::package_require('tile'); Tkx::ttk__setTheme('xpnative');#Tkx::tile__setTheme('xpnative'); my $logger = Log::Log4perl->get_logger; $logger ->level( $Log::Log4perl::INFO ); ## HA! my $appender = Log::Log4perl::Appender::String2->new; $logger->add_appender($appender); my $mw = Tkx::widget->new("."); my $t = $mw->new_text( -padx => 5, -pady => 5, #~ -textvariable => $appender->string_ref, # text doesn't have + textvariable, grr -background => "white", ); $t->g_pack; $appender->tktext( $t ); # text doesn't have textvariable, grr my $b = $mw->new_ttk__button( -text => 'Hello, world', -command => sub { $logger->info("hi"); #~ $mw->g_destroy; }, ); $b->g_pack; $b->configure(); $logger->info("it begins"); Tkx::MainLoop(); } BEGIN { #~ $INC{'TextTextVariable.pm'} = __FILE__; ## http://wiki.tcl.tk/1917# Text variable for text widget $INC{'Log/Log4perl/Appender/String2.pm'} = __FILE__; package Log::Log4perl::Appender::String2; use Log::Log4perl::Appender; our @ISA = qw(Log::Log4perl::Appender); ################################################## # Log dispatcher writing to a string buffer ################################################## ################################################## sub new { ################################################## my $proto = shift; my $class = ref $proto || $proto; my %params = @_; my $self = { name => "unknown name", string => "", %params, }; bless $self, $class; } ################################################## sub log { ################################################## #~ my $self = shift; #~ my %params = @_; # copied from Log::Log4perl::Appender::Str +ing, wtf my ($self, $p, $category, $level, $cache) = @_; my %params = %$p; if( my $status_text = $self->{tktext} ){ warn "wtf is wtf "; # text control has to be enabled to write to it. $status_text->configure(-state => "normal"); $status_text->insert("end", $params{message} ); $status_text->see("end"); # Don't want the user editing this... $status_text->configure(-state => "disabled"); eval { $status_text->update(); 1} or eval { Tkx::update(); + }; } else { $self->{string} .= $params{message}; } } ################################################## sub string { ################################################## my($self, $new) = @_; if(defined $new) { $self->{string} = $new; } return $self->{string}; } ################################################## sub tktext { ################################################## my($self, $new) = @_; if(defined $new) { $self->{tktext} = $new; } return $self->{tktext}; } ################################################## sub string_ref { ################################################## my($self ) = @_; return if $self->{tktext}; return \$self->{string}; } 1; }

      Sadly, I'm not currently smart enough to do so.

      I've decided to go a different route, (which I'm ALSO having problems with) and will have a string appender tied to a label (which does use a textvariable), but currently I can't seem to get l4p to populate the string appender as I expect it to.

      To view the log, I'm just going to place a button on the UI to open the file in a text editor that can be set from a conf file.

Re: Log4perl and Tkx
by Anonymous Monk on Nov 23, 2011 at 21:13 UTC
    Would pointing a Log::Log4perl::Appender::String object at the scalar holding your textbox data do the job, or am I misunderstanding your question?

    TJD

      Unfortunately, you can't do that is my understanding of the text widget. Here's the code for creating the text area and modifying the text in the widget, after creating the base canvas:
      my $status_text_scrollbar = $logging_grid->new_ttk__scrollbar(); my $status_text = $logging_grid->new_tk__text(); $status_text->configure( -width => 80, -height => 10, -yscrollcommand => [$status_text_scrollbar, "set"], -state => "disabled", ); $status_text_scrollbar->configure( -command => [$status_text, "yview"], -orient => "vertical", ); update_tkx('Update the text in the box, please'); sub update_tkx { my $status_text_string = $_[0]; # text control has to be enabled to write to it. $status_text->configure(-state => "normal"); $status_text->insert("end", $status_text_string); $status_text->see("end"); # Don't want the user editing this... $status_text->configure(-state => "disabled"); Tkx::update(); }
      Ideally, it would be nice to be able to call update_tkx() when the l4p event fires. I don't know how to do that, and feed it data from an appender. Otherwise, I'll have to call the sub with the data in the code every time I log something. Not undoable, but it doesn't really help me simplify the logging as much as I'd like.