diff options
Diffstat (limited to 'src/pmdas/dtsrun/pmdadtsrun.pl')
-rw-r--r-- | src/pmdas/dtsrun/pmdadtsrun.pl | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/src/pmdas/dtsrun/pmdadtsrun.pl b/src/pmdas/dtsrun/pmdadtsrun.pl new file mode 100644 index 0000000..9d09d6e --- /dev/null +++ b/src/pmdas/dtsrun/pmdadtsrun.pl @@ -0,0 +1,341 @@ +# +# Copyright (c) 2009 Aconex. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +use strict; +use warnings; +use PCP::PMDA; +use Time::Local; + +my $pmda = PCP::PMDA->new('dtsrun', 102); + +my ( $package, $package_starttime, $instance_refresh ); +my $package_indom = 0; # instance domain for DTS package +my @package_instances = (); +my ( $step, $step_starttime ); +my $steps_indom = 1; # instance domain for DTS package steps +my @steps_instances = (); + +use vars qw ( %lastpkg_times %lastpkg_stamp %allpkgs_times %allpkgs_count + %laststep_times %laststep_stamp %laststep_offset + %laststep_status %laststep_message %allsteps_times + %allsteps_count %allsteps_errors %allpkgs_delta + %packages %steps + ); + +sub parsetime +{ + shift; + #$pmda->log("parsetime got dtsrun timestamp: $_"); + m|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) (\w+)|; + my ($mm, $dd, $year, $hr, $min, $sec, $ampm) = ($1,$2,$3,$4,$5,$6,$7); + $hr += 12 unless ($ampm eq 'AM'); + $hr -= 1; # range 0..23 (hours) + $mm -= 1; # range 0..11 (months) + my $tm = timelocal($sec,$min,$hr,$dd,$mm,$year); + return $tm; +} + +sub dtsrun_parser +{ + ( undef, $_ ) = @_; + + s/\r//g; # cull Windows line endings + #$pmda->log("dtsrun_parser got line: $_"); + + if (/^Step '(\S+)' (.*)/) { + $step = "$package/$1"; + if (defined($steps{$step})) { + $allsteps_count{$step}++; + } else { # new step instance + $steps{$step} = 1; + $allsteps_times{$step} = 0; + $allsteps_count{$step} = 1; + $allsteps_errors{$step} = 0; + $laststep_times{$step} = 0; + $laststep_stamp{$step} = ''; + $laststep_offset{$step} = 0; + $laststep_status{$step} = -1; + $laststep_message{$step} = ''; + $instance_refresh = 1; + } + if ($2 eq 'succeeded') { + $laststep_status{$step} = 0; + } else { + $laststep_status{$step} = -1; + $allsteps_errors{$step}++; + } + $laststep_message{$step} = $2; + } + elsif (/^Step Execution Started: (.*)/) { + $step_starttime = parsetime($1); + $laststep_stamp{$step} = $1; + $laststep_offset{$step} = $step_starttime - $package_starttime; + } + elsif (/^Total Step Execution Time: (\S+) seconds/) { + $laststep_times{$step} = $1; + $allsteps_times{$step} += $1; + } + elsif (/^Package Name: (\w+)/) { + $package = $1; + if (defined($packages{$package})) { + $allpkgs_count{$package}++; + } else { # new package instance + $packages{$package} = 1; + $allpkgs_delta{$package} = 0; + $allpkgs_times{$package} = 0; + $allpkgs_count{$package} = 1; + $lastpkg_times{$package} = 0; + $lastpkg_stamp{$package} = ''; + $instance_refresh = 1; + } + } + elsif (/^Execution Started: (.*)/) { + my $latest = parsetime($1); + if (defined($package_starttime) && $package_starttime >= 0) { + $allpkgs_delta{$package} = $latest - $package_starttime; + } else { + $allpkgs_delta{$package} = -1; + } + $package_starttime = $latest; + $lastpkg_stamp{$package} = $1; + } + elsif (/^Total Execution Time: (\S+) seconds/) { + $lastpkg_times{$package} = $1; + $allpkgs_times{$package} += $1; + } + elsif (/^\*\*\*/) { + # end section, cleanup global state + undef $step; + undef $package; + } +} + +sub dtsrun_instance +{ + my ( $pkgcount, $stepcount ); + + #$pmda->log("dtsrun_instance"); + return unless (defined($instance_refresh) && $instance_refresh); + + @package_instances = (); + @steps_instances = (); + + $pkgcount = $stepcount = 0; + foreach my $pkgname (keys(%packages)) { + push @package_instances, $pkgcount++, $pkgname; + foreach my $stepname (sort keys(%steps)) { + push @steps_instances, $stepcount++, $stepname; + } + } + + #$pmda->log("dtsrun_instance: $pkgcount packages, $stepcount steps"); + $pmda->replace_indom($package_indom, \@package_instances); + $pmda->replace_indom($steps_indom, \@steps_instances); + $instance_refresh = 0; +} + +sub dtsrun_fetch_callback +{ + my ($cluster, $item, $inst) = @_; + my $instance; + + #$pmda->log("dtsrun_fetch_callback for PMID: $cluster.$item ($inst)"); + if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } + + if ($cluster == 0 || $cluster == 1 || $cluster == 4) { + $instance = pmda_inst_name($package_indom, $inst); + } else { + $instance = pmda_inst_name($steps_indom, $inst); + } + if (!defined($instance)) { return (PM_ERR_INST, 0); } + #$pmda->log("dtsrun_fetch_callback using instance $instance"); + + if ($cluster == 0) { + # dtsrun.package.last.time + if ($item == 0) { return ($lastpkg_times{$instance}, 1); } + # dtsrun.package.last.timestamp + elsif ($item == 1) { return ($lastpkg_stamp{$instance}, 1); } + } + elsif ($cluster == 1) { + # dtsrun.package.total.time + if ($item == 0) { return ($allpkgs_times{$instance}, 1); } + # dtsrun.package.total.count + elsif ($item == 1) { return ($allpkgs_count{$instance}, 1); } + } + elsif ($cluster == 2) { + # dtsrun.package.steps.last.time + if ($item == 0) { return ($laststep_times{$instance}, 1); } + # dtsrun.package.steps.last.timestamp + if ($item == 1) { return ($laststep_stamp{$instance}, 1); } + # dtsrun.package.steps.last.offset + if ($item == 2) { return ($laststep_offset{$instance}, 1); } + # dtsrun.package.steps.last.status + if ($item == 3) { return ($laststep_status{$instance}, 1); } + # dtsrun.package.steps.last.message + if ($item == 4) { return ($laststep_message{$instance}, 1); } + } + elsif ($cluster == 3) { + # dtsrun.package.steps.total.time + if ($item == 0) { return ($allsteps_times{$instance}, 1); } + # dtsrun.package.steps.total.count + if ($item == 1) { return ($allsteps_count{$instance}, 1); } + # dtsrun.package.steps.total.errors + if ($item == 2) { return ($allsteps_errors{$instance}, 1); } + } + elsif ($cluster == 4) { + # dtsrun.package.interval + if ($item == 0) { return ($allpkgs_delta{$instance}, 1); } + } + return (PM_ERR_PMID, 0); +} + +sub dtsrun_setup_metrics +{ + $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_FLOAT, $package_indom, + PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.lastrun.time', '', + 'Time taken for DTS package to complete the last time it was run'); + $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, $package_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'dtsrun.package.lastrun.timestamp', '', + 'Time stamp (string) of the last package run for each DTS package'); + + $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_FLOAT, $package_indom, + PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.total.time', '', + 'Cumulative time taken to date for all DTS package runs.'); + $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, $package_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'dtsrun.package.total.count', '', + 'Cumulative count of all DTS package runs to date.'); + + $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $steps_indom, + PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.steps.last.time', '', + 'Time taken to complete the last iteration of each step.'); + $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_STRING, $steps_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'dtsrun.package.steps.last.timestamp', '', + 'Time of completion of the last iteration of each step.'); + $pmda->add_metric(pmda_pmid(2,2), PM_TYPE_U32, $steps_indom, + PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.steps.last.offset', '', + 'Offset from package start time for this step, in seconds.'); + $pmda->add_metric(pmda_pmid(2,3), PM_TYPE_32, $steps_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'dtsrun.package.steps.last.status', '', + 'Indicator of success (0) or failure of last run for each step.'); + $pmda->add_metric(pmda_pmid(2,4), PM_TYPE_STRING, $steps_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'dtsrun.package.steps.last.message', '', + 'Message string used to determine status of last run for each step.'); + + $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_FLOAT, $steps_indom, + PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.steps.total.time', '', + 'Cumulative count of time taken for runs of each DTS package step.'); + $pmda->add_metric(pmda_pmid(3,1), PM_TYPE_U32, $steps_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'dtsrun.package.steps.total.count', '', + 'Cumulative count of runs of each DTS package step.'); + $pmda->add_metric(pmda_pmid(3,2), PM_TYPE_U32, $steps_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'dtsrun.package.steps.total.errors', '', + 'Cumulative count of errors observed for each DTS package step.'); + + $pmda->add_metric(pmda_pmid(4,0), PM_TYPE_32, $package_indom, + PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), + 'dtsrun.package.interval', '', + 'Time between consecutive observations of each DTS package run. Unknown is -1.'); +} + +sub dtsrun_setup_instances +{ + $package_indom = $pmda->add_indom($package_indom, [], '', ''); + $steps_indom = $pmda->add_indom($steps_indom, [], '', ''); +} + +my $logfile = ''; +if (!defined($ENV{PCP_PERL_PMNS} && !defined($ENV{PCP_PERL_DOMAIN}))) { + die "No dtsrun statistics file specified\n" unless (defined($ARGV[0])); + $logfile = $ARGV[0]; + die "Cannot find a valid dtsrun statistics file\n" unless -f $logfile; +} +$pmda->log("Using logfile: $logfile"); + +dtsrun_setup_metrics; +dtsrun_setup_instances; + +$pmda->add_tail($logfile, \&dtsrun_parser, 0); +$pmda->set_fetch(\&dtsrun_instance); +$pmda->set_instance(\&dtsrun_instance); +$pmda->set_fetch_callback(\&dtsrun_fetch_callback); +$pmda->set_user('pcp'); +$pmda->run; + +=pod + +=head1 NAME + +pmdadtsrun - Data Transformation Services process (dtsrun) log file PMDA + +=head1 DESCRIPTION + +B<pmdadtsrun> is a Performance Metrics Domain Agent (PMDA) which +exports metric values from the DTS run executable, which is a data +transformation server, used with SQL Server. +Further details on DTS can be found at http://www.dtssql.com/. + +=head1 INSTALLATION + +If you want access to the names and values for the dtsrun performance +metrics, do the following as root: + + # cd $PCP_PMDAS_DIR/dtsrun + # ./Install + +If you want to undo the installation, do the following as root: + + # cd $PCP_PMDAS_DIR/dtsrun + # ./Remove + +B<pmdadtsrun> is launched by pmcd(1) and should never be executed +directly. The Install and Remove scripts notify pmcd(1) when +the agent is installed or removed. + +=head1 FILES + +=over + +=item /var/log/dtsrun.log + +log file showing status and elapsed times exported from dtsrun + +=item $PCP_PMDAS_DIR/dtsrun/Install + +installation script for the B<pmdadtsrun> agent + +=item $PCP_PMDAS_DIR/dtsrun/Remove + +undo installation script for the B<pmdadtsrun> agent + +=item $PCP_LOG_DIR/pmcd/dtsrun.log + +default log file for error messages from B<pmdadtsrun> + +=back + +=head1 SEE ALSO + +pmcd(1). |