Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Service monitor with Perl and PerlSvc

by perlsage (Scribe)
on Apr 17, 2003 at 11:25 UTC ( #251168=sourcecode: print w/replies, xml ) Need Help??
Category: Win32 Stuff
Author/Contact Info perlsage
Description: A simple service monitor using Perl and PerlSvc, reads settings from registry, monitors services.

Features:
  • windows service.
  • error reporting to windows eventlog.
  • service status reporting to database using ODBC
Suggestions for improvements are welcome, my first post <:)
# Svcwatch is meant to be used with PerlSvc to create the actual
# service.
#%status = (
#  0 => 'unknown',
#  1 => 'stopped',
#  2 => 'starting',
#  3 => 'stopping',
#  4 => 'running',
#  5 => 'resuming',
#  6 => 'pausing',
#  7 => 'paused',
#);

package PerlSvc;
use Win32::Service;
use Win32::TieRegistry(Delimiter=>"/");
use DBI;
use DBD::ODBC;
use Win32::EventLog;

# the short name by which your service will be known (cannot be 'my')
our $Name = "svcwatch";

# the display name. This is the name that the Windows Control Panel
# will display (cannot be 'my')
our $DisplayName = "Service Watch";



$|=1;
our $cn=Win32::NodeName();

#modify this to change the location of the settings
$regkey="LMachine/Software/SvcWatch";

# the startup routine is called when the service starts
sub Startup {
    Win32::Service::GetServices("", \%tmp);
    %svc=reverse %tmp;
    @reg=split /,/,my $reg=$Registry->{$regkey}->GetValue("services");
    $pwd=$Registry->{$regkey}->GetValue("Pwd")||die $!;
    $srv=$Registry->{$regkey}->GetValue("Srv")||die $!;
    $uid=$Registry->{$regkey}->GetValue("Uid")||die $!;
    while (ContinueRun()) {
        foreach (@reg){
            if (Win32::Service::GetStatus("",$_,\%{$_})){
                unless(${$_}{'CurrentState'} eq ${$_}{'Previous'}){
                    ${$_}{'Previous'}=${$_}{'CurrentState'};
                    $dsn="driver=\{SQL Server\}\;Server=$srv\;UID\=$ui
+d\;PWD\=$pwd\;";
                    $dbh=DBI->connect("DBI:ODBC:$dsn");
                    my $sname=$svc{$_};
                    my $state=${$_}{'CurrentState'};
if ($dbh){
    $exec=$dbh->prepare("insert into serviceinfo (server, service, sta
+tus) values ('$cn', '$sname', $state)");
    $exec->execute;
    $exec->finish;}else{
    Win32::EventLog::WriteEventLog ($ENV{Computer}, "$DisplayName", "1
+", "0", "1", "\n$DBI::errstr\n", "\n\$! $!\n$DBI::errstr\n");
    }
}
}else
    {
        unless (${$_} eq "1"){
            ${$_}=1;
            $dsn="driver=\{SQL Server\}\;Server=$srv\;UID\=$uid\;PWD\=
+$pwd\;";
            $dbh=DBI->connect("DBI:ODBC:$dsn");
            if ($dbh){
                $exec=$dbh->prepare("insert into serviceinfo (server, 
+service, status) values ('$cn', '$_', 0)");
                $exec->execute;
                $exec->finish;}else {#write to eventlog $dbi::errstr
                Win32::EventLog::WriteEventLog ($ENV{Computer}, "$Disp
+layName", "1", "0", "1", "\n$DBI::errstr\n", "\n\$! $!\n$DBI::errstr\
+n");
                }
        }
    }
}
sleep(5);
}
}

sub Install {
    # add your additional install messages or functions here
    print "The $Name Service has been installed.\n";
    print "Start the service with the command: net start $Name\n";
    my $reg=$Registry->{$regkey}->GetValue("services")||die $!;
    print "\nWatching for...\n\t".(join ",",$reg);
}
sub Remove {
# add your additional remove messages or functions here
print "The $Name service has been removed.\n";
}

sub Help {
# add your additional help messages or functions here
print "No help available.\n";
}
Replies are listed 'Best First'.
Re: Service monitor with Perl and PerlSvc
by Jenda (Abbot) on Apr 17, 2003 at 19:55 UTC

    This is a respose to both Juerd and crenz so I'll put the node here.

    # # the short name by which your service will be known (cannot be 'my')
    # Please document *why* something is not possible, instead of just "can't do this".

    Because otherwise PerlSvc would not be able to read it.

    # Do check the return values. In a module, it's better to turn PrintError off and handle errors yourself.

    This ain't a module. The PerlSvc tool requires that the service name and the callbacks are in package PerlSvc. I think the info should contain a pointer to the PerlSvc docs and the "Perl Development Kit" should also be mentioned to prevent confusion.

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature

Re: Service monitor with Perl and PerlSvc
by Juerd (Abbot) on Apr 17, 2003 at 16:20 UTC

    package PerlSvc; use Win32::Service; use Win32::TieRegistry(Delimiter=>"/"); use DBI; use DBD::ODBC; use Win32::EventLog;

    use strict; is missing.

    # the short name by which your service will be known (cannot be 'my')

    Please document *why* something is not possible, instead of just "can't do this".

    ${$_}{'CurrentState'}

    I think $_->{'CurrentState'} is easier to read. (I'd even leave out the quotes.)

    $dsn="driver=\{SQL Server\}\;Server=$srv\;UID\=$uid\;PWD\=$pwd\;";

    It's clearer and much easier to read if you don't escape things that don't need escaping: $dsn = "driver={SQL Server};Server=$src;UID=$uid;PWD=$pwd;";

    $exec=$dbh->prepare("..."); $exec->execute;

    Do check the return values. In a module, it's better to turn PrintError off and handle errors yourself.

    $exec=$dbh->prepare("... values ('$cn', '$sname', $state)");

    Don't interpolate arbitrary values in a query. Use placeholders instead.

    $exec->finish;}else{

    Why does the else not have its own line?

    } }else

    No two closing curlies can be in the same column in proper indented code.

    unless (${$_} eq "1"){

    Are you sure you want a string equality test? Not a numeric one? Or maybe even a boolean test? (unless ($$_) { ... })

    $dsn="driver=\{SQL Server\}\;Server=$srv\;UID\=$uid\;PWD\= +$pwd\;";

    You're repeating code. It's better to put that string in a more global variable. I personally like having a sub 'db' that returns a dbh: sub db { DBI->connect("dsn here") }

    } sleep(5); } }

    Again: this should never happen.

    Win32::Service::GetServices("", \%tmp); ... if (Win32::Service::GetStatus("",$_,\%{$_})){

    You sometimes have a space after comma, you sometimes don't. Whatever style you choose, be consistent. (I like having a space after commas)

    "$DisplayName"

    Those quotes should not be necessary. Use plain $DisplayName instead.

    print "No help available.\n";

    Very helpful :)

    In general: learn about indenting, use strict, learn about writing modules, get to know Perl a little better. Good luck and have fun.

    Juerd
    - http://juerd.nl/
    - spamcollector_perlmonks@juerd.nl (do not use).
    

Re: Service monitor with Perl and PerlSvc
by crenz (Priest) on Apr 17, 2003 at 18:29 UTC

    Hello perlsage, congrats for your first post :)

    In addition to the observations Juerd made, I have two more nits to pick:

    • Instead of modifying and customizing the module for each service you want to monitor, why not make an object-oriented interface to let people customize their own services? The perlboot and perltoot manpages have some examples.
    • "Perlsvc" is quite misleading. My first association was D.J.Bernsteins daemontools package for Unix :). How about naming it something like Win32::Service::Monitor? (that's not a good name yet, but maybe a starter.)

    I hope these comments help you to improve your code. Feel free to update this node with improved code or post some questions if you need help with any of the aspects we mentioned.

    Have fun!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://251168]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (7)
As of 2020-09-22 22:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    If at first I donít succeed, I Ö










    Results (130 votes). Check out past polls.

    Notices?