Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

My Code Is Functional...But Not Tidy :(

by Anonymous Monk
on Apr 23, 2003 at 17:26 UTC ( [id://252633]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Peeps,

I have wrote the following code, it works, but it is laim coding. Would someone show me a better way of writing this (or parts of this) script.

#!/usr/bin/perl use IO::Socket::INET; $time = localtime; $users = grep{ -d $_ } glob('/home/*'); $users = $users + 600; $mx1pop3 = IO::Socket::INET->new( Timeout => 1, PeerAddr => 'mail.test.com', PeerPort => 110, Proto => 'tcp'); $mx1smtp = IO::Socket::INET->new( Timeout => 1, PeerAddr => 'mail.test.com', PeerPort => 25, Proto => 'tcp'); $mx1web = IO::Socket::INET->new( Timeout => 1, PeerAddr => 'test.com', PeerPort => 80, Proto => 'tcp'); $mx1dns = IO::Socket::INET->new( Timeout => 1, PeerAddr => 'test.com', PeerPort => 53, Proto => 'tcp'); if ($mx1pop3 and $mx1smtp) { $mail = 'Up'; } else { $mail = 'Down'; } if ($mx1web) { $web = 'Up'; } else { $web = 'Down'; } if ($mx1dns) { $dns = 'Up'; } else { $dns = 'Down'; } print "Content-type: text/html\n\n"; print "<p><font size=1 face=Arial, Helvetica, sans-serif>$time</font>< +/p>\n" ; print "<p><font size=1 face=Arial, Helvetica, sans-serif>Mail Servers: + $mail<br>Web Servers: $web<br>DNS Servers: $dns</font></p>\n" ; print "<p><font size=1 face=Arial, Helvetica, sans-serif>Active Users: + $users</font></p>\n" ;

Replies are listed 'Best First'.
Re: My Code Is Functional...But Not Tidy :(
by grep (Monsignor) on Apr 23, 2003 at 17:46 UTC
    This is a little cleaner, but I would recommend not reinventing the wheel. Nagios is an excellent system monitoring product.

    #!/usr/local/bin/perl use strict; use warnings; use IO::Socket::INET; my %config = ( 'mail.test.com' => [ 'smtp','pop3' ], 'localhost' => [ 'http','dns' ] ); my %check; foreach my $host (keys %config) { foreach my $port (@{$config{$host}}) { my $host_port = "$host".'_'."_$port"; $check{$host_port} = IO::Socket::INET->new( Timeout => 1, PeerAddr => $host, PeerPort => $port, Proto => 'tcp'); } } foreach my $check_it (keys %check) { if ($check{$check_it}) { print "$check_it is ok\n"; } }


    grep
    Mynd you, mønk bites Kan be pretti nasti...
•Re: My Code Is Functional...But Not Tidy :(
by merlyn (Sage) on Apr 23, 2003 at 17:50 UTC
    The core testing part can be something like:
    use IO::Socket::Inet; for ( ['Mail Servers', 'mail.test.com:110', 'mail.test.com:25'], ['Web Servers', 'test.com:80'], ['DNS Servers', 'test.com:53'], ) { my ($message, @ports) = @$_; my $good = 1; for (@ports) { $good = 0, last unless IO::Socket::INET->new($port); } print "$message: ", $good ? "Up" : "Down"; print "\n"; }
    You'll have to add the HTML yourself. {grin}

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: My Code Is Functional...But Not Tidy :(
by pfaut (Priest) on Apr 23, 2003 at 17:47 UTC

    Here's how I would do it. YMMV.

    #!/usr/bin/perl -w use strict; use IO::Socket::INET; my %services = ( pop => [ 'mail.test.com', 110 ], smtp => [ 'mail.test.com', 25 ], web => [ 'test.com', 80 ], dns => [ 'test.com', 53 ], ); my %status; $status{$_} = 'Up' for keys %services; while (my ($name,$svc) = each %services) { my $sock = IO::Socket::INET->new(Timeout=>1, PeerAddr => $svc->[0], PeerPort => $svc->[1], Proto => 'tcp' ) or $status{$name} = 'Down'; } while (my ($name,$sts) = each %status) { print "$name server is $sts\n"; }
    90% of every Perl application is already written.
    dragonchild
Re: My Code Is Functional...But Not Tidy :(
by dragonchild (Archbishop) on Apr 23, 2003 at 17:48 UTC
    Just replacing the middle part:
    # Above all others, add: use strict; # Some stuff here my %connection = ( pop3 => { PeerAddr => 'mail.test.com', PeerPort => 110, }, # Add the others here, like above ); my %socket; while (my ($name, $values) = each %connections) { $socket{$name} = IO::Socket::INET->new( Timeout => 1, Proto => 'tcp', ( map { $_ => $values->{$_} } keys %$values ), ); } my $UP = 'Up'; my $DOWN = 'Down'; my $mail = ($socket{pop3} && $socket{smtp} ? $UP : $DOWN); # Do other checks here
    Oh - use CGI::Lite for your HTML outputting, or, better, use HTML::Template. Always try to separate presentation from logic.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: My Code Is Functional...But Not Tidy :(
by Trimbach (Curate) on Apr 23, 2003 at 17:51 UTC
    Ugliness is in the eye of the beholder. There's lots and lots (and lots) of different ways to do it.. I'd probably use a hash-of-hashes, but hey, what you've got works, it's easy to maintain, and it is brutally clear what it does and how it does it. TMTOWTDI, and all that.

    Personally I wouldn't sweat it unless you were planning on vastly expanding this program, or were trying to make it into a more generalized solution, and if that's the case you're definitely in wheel-reinvention territory. :-)

    Gary Blackburn
    Trained Killer

Re: My Code Is Functional...But Not Tidy :(
by Solo (Deacon) on Apr 23, 2003 at 20:24 UTC
    How about a Config::IniFiles solution? ...

    #!/usr/bin/perl use IO::Socket::INET; use Config::IniFiles; my $cfg = Config::IniFiles->new(-file => *DATA); my %socket = (); for my $monitor ( $cfg->GroupMembers('Monitor') ) { my ($name) = $monitor =~ /Monitor (.+)/; $socket{$name} = IO::Socket::INET->new( Timeout => $cfg->val( $monitor, 'Timeout' ), PeerAddr => $cfg->val( $monitor, 'PeerAddr' ), PeerPort => $cfg->val( $monitor, 'PeerPort' ), Proto => $cfg->val( $monitor, 'Proto' ), ); } # ... __DATA__ [Monitor Pop3] Timeout = 1 PeerAddr = 'mail.test.com' PeerPort = 110 Proto = 'tcp' [Monitor SMTP] Timeout = 1 PeerAddr = 'mail.test.com' PeerPort = 25 Proto = 'tcp' [Monitor Web] Timeout = 1 PeerAddr = 'test.com' PeerPort = 80 Proto = 'tcp' [Monitor DNS] Timeout = 1 PeerAddr = 'test.com' PeerPort = 53 Proto = 'tcp'

    Naturally, the DATA filehandle could (should) be replaced with a real file--and you magically gain the benefit of multiple configurations. Not to mention all the bells & whistles of IniFiles, like defaults and updates.

    Update: fixed small typo

    --Solo

    --
    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.
Re: My Code Is Functional...But Not Tidy :(
by Fletch (Bishop) on Apr 23, 2003 at 19:21 UTC
Re: My Code Is Functional...But Not Tidy :(
by Anonymous Monk on Apr 24, 2003 at 17:02 UTC
    This is the perfect moment for a Factory pattern. Write a function that returns IO::Socket::Inet objects, but you only pass the parameters along.

    Your factory, is an engine of sorts. How it figures out what object you want is up to you. You can make configuration files, as someone suggested and your factoury would do, Factory->new( 'http://test.com' ) for port 80, or Factory->new('smtp://test.com').

    Or you can write a Factory that takes all the parameters.

    All in all, it'd reduce the code down to ...

    $web = Factory->new( some parameters, a url, or numbers and hosts );
    $smtp = ....
    $something = ....

    But otherwise, it's not THAT ugly in truth. YOu formated your code, it's easy to read. The factory thing is all i can really suggest.
      Isn't that what IO::Socket::Inet::new is already doing? I don't see how your factory method would be doing anything different. And for what it's worth, the original poster's code is some of the cleanest Perl I've ever seen.
        Well, if you integrate configuration files into the factory, your code becomes cleaner. Now lets say you stop using IO::Socket::Inet but switch to something else, you don't have to change from using IO::Socket everywhere, just change how the factory works.
        It is clean, yes. But, it's not very extensible, configurable, or customizable. It doesn't take advantage of shared snippets to make maintenance easier. That's what most of the responses have been about. Taking it to the next level, if that's what's desirable and desired.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://252633]
Approved by sschneid
Front-paged by Trimbach
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-04-24 12:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found