diff options
Diffstat (limited to 'src/pmdas/mssql')
-rw-r--r-- | src/pmdas/mssql/GNUmakefile | 53 | ||||
-rw-r--r-- | src/pmdas/mssql/Install | 34 | ||||
-rw-r--r-- | src/pmdas/mssql/Remove | 29 | ||||
-rw-r--r-- | src/pmdas/mssql/pmdamssql.pl | 315 |
4 files changed, 431 insertions, 0 deletions
diff --git a/src/pmdas/mssql/GNUmakefile b/src/pmdas/mssql/GNUmakefile new file mode 100644 index 0000000..c76670e --- /dev/null +++ b/src/pmdas/mssql/GNUmakefile @@ -0,0 +1,53 @@ +#!gmake +# +# Copyright (c) 2011 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +IAM = mssql +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +LSRCFILES = Install Remove pmda$(IAM).pl + +ifneq ($(POD2MAN),) +MAN_SECTION = 1 +MAN_PAGES = pmda$(IAM).$(MAN_SECTION) +MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) +endif + +LDIRT = domain.h root pmns *.log $(MAN_PAGES) + +default: check_domain $(MAN_PAGES) + +pmda$(IAM).1: pmda$(IAM).pl + $(POD_MAKERULE) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PMDADIR) + $(INSTALL) -m 755 Install Remove $(PMDADIR) + $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl + @$(INSTALL_MAN) + +default_pcp : default + +install_pcp : install + +check_domain: ../../pmns/stdpmid + $(DOMAIN_PERLRULE) diff --git a/src/pmdas/mssql/Install b/src/pmdas/mssql/Install new file mode 100644 index 0000000..bd222fa --- /dev/null +++ b/src/pmdas/mssql/Install @@ -0,0 +1,34 @@ +#! /bin/sh +# +# Copyright (c) 2011 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. +# +# Install the MSSQL PMDA +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=mssql +perl_opt=true +daemon_opt=false +forced_restart=false + +perl -e "use DBI" 2>/dev/null +if test $? -ne 0; then + echo "Perl database interface (DBI) is not installed" + exit 1 +fi + +pmdaSetup +pmdaInstall +exit 0 diff --git a/src/pmdas/mssql/Remove b/src/pmdas/mssql/Remove new file mode 100644 index 0000000..1408c07 --- /dev/null +++ b/src/pmdas/mssql/Remove @@ -0,0 +1,29 @@ +#! /bin/sh +# +# Copyright (c) 2011 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Remove the MSSQL PMDA +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=mssql + +pmdaSetup +pmdaRemove +exit 0 diff --git a/src/pmdas/mssql/pmdamssql.pl b/src/pmdas/mssql/pmdamssql.pl new file mode 100644 index 0000000..e82fb62 --- /dev/null +++ b/src/pmdas/mssql/pmdamssql.pl @@ -0,0 +1,315 @@ +# +# Copyright (c) 2011 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 DBI; + +my $server = 'localhost'; +my $database = 'PCP'; +my $username = 'dbmonitor'; +my $password = 'dbmonitor'; + +# Configuration files for overriding the above settings +for my $file ( '/etc/pcpdbi.conf', # system defaults (lowest priority) + pmda_config('PCP_PMDAS_DIR') . '/mssql/mssql.conf', + './mssql.conf' ) { # current directory (high priority) + eval `cat $file` unless ! -f $file; +} + +use vars qw( $pmda $dbh ); +use vars qw( $sth_os_memory_clerks ); +use vars qw( $sth_virtual_file_stats @virtual_file_stats ); +use vars qw( $sth_total_running_user_processes @total_running_user_processes ); +use vars qw( $sth_os_memory_clerks @os_memory_clerks ); +use vars qw( $sth_os_workers_waiting_cpu @os_workers_waiting_cpu ); +my $database_indom = 0; +my @database_instances; + +sub mssql_connection_setup +{ + #$pmda->log("mssql_connection_setup\n"); + + if (!defined($dbh)) { + $dbh = DBI->connect("DBI:Sybase:server=$server", $username, $password); + if (defined($dbh)) { + $pmda->log("MSSQL connection established\n"); + $sth_virtual_file_stats = $dbh->prepare( + "select db_name(database_id), cast(num_of_reads as numeric), cast(num_of_bytes_read as numeric)," . + " cast(io_stall_read_ms as numeric), cast(num_of_writes as numeric)," . + " cast(num_of_bytes_written as numeric), cast(io_stall_write_ms as numeric)," . + " cast(size_on_disk_bytes as numeric) " . + "from sys.dm_io_virtual_file_stats(DB_ID(''),1)"); + $sth_os_memory_clerks = $dbh->prepare( + "SELECT SUM(multi_pages_kb + virtual_memory_committed_kb + shared_memory_committed_kb + awe_allocated_kb)" . + " from sys.dm_os_memory_clerks WHERE type IN " . + "('MEMORYCLERK_SQLBUFFERPOOL', 'MEMORYCLERK_SQLQUERYCOMPILE'," . + " 'MEMORYCLERK_SQLQUERYEXEC', 'MEMORYCLERK_SQLQUERYPLAN')" . + " group by type order by type"); + $sth_total_running_user_processes = $dbh->prepare( + "SELECT count(*) FROM sys.dm_exec_requests " . + "WHERE session_id >= 51 AND status = 'running'"); + $sth_os_workers_waiting_cpu = $dbh->prepare( + "SELECT ISNULL(COUNT(*),0) FROM sys.dm_os_workers AS workers " . + "INNER JOIN sys.dm_os_schedulers AS schedulers " . + "ON workers.scheduler_address = schedulers.scheduler_address " . + "WHERE workers.state = 'RUNNABLE' AND schedulers.scheduler_id < 255"); + } + } +} + +sub mssql_os_memory_clerks_refresh +{ + #$pmda->log("mssql_os_memory_clerks_refresh\n"); + + @os_memory_clerks = (); # clear any previous contents + if (defined($dbh)) { + $sth_os_memory_clerks->execute(); + my $result = $sth_os_memory_clerks->fetchall_arrayref(); + for my $i (0 .. $#{$result}) { + $os_memory_clerks[$i] = $result->[$i][0]; + } + } +} + +sub mssql_virtual_file_stats_refresh +{ + #$pmda->log("mssql_virtual_file_stats_refresh\n"); + + @virtual_file_stats = (); # clear any previous contents + @database_instances = (); + + if (defined($dbh)) { + $sth_virtual_file_stats->execute(); + my $result = $sth_virtual_file_stats->fetchall_arrayref(); + + for my $i (0 .. $#{$result}) { + $database_instances[($i*2)] = $i; + $database_instances[($i*2)+1] = "$result->[$i][0]"; + $virtual_file_stats[$i] = $result->[$i]; + } + + $pmda->replace_indom( $database_indom, \@database_instances ); + } +} + +sub mssql_total_running_user_processes +{ + #$pmda->log("mssql_total_running_user_processes\n"); + + @total_running_user_processes = (); # clear any previous contents + if (defined($dbh)) { + $sth_total_running_user_processes->execute(); + my $result = $sth_total_running_user_processes->fetchall_arrayref(); + @total_running_user_processes = ( $result->[0][0] ); + } +} + +sub mssql_os_workers_waiting_cpu_refresh +{ + #$pmda->log("mssql_os_workers_refresh\n"); + + @os_workers_waiting_cpu = (); # clear any previous contents + if (defined($dbh)) { + $sth_os_workers_waiting_cpu->execute(); + my $result = $sth_os_workers_waiting_cpu->fetchall_arrayref(); + @os_workers_waiting_cpu = ( $result->[0][0] ); + } +} + +sub mssql_refresh +{ + my ($cluster) = @_; + + #$pmda->log("mssql_refresh $cluster\n"); + + if ($cluster == 0) { mssql_virtual_file_stats_refresh; } + elsif ($cluster == 1) { mssql_os_memory_clerks_refresh; } + elsif ($cluster == 2) { mssql_total_running_user_processes; } + elsif ($cluster == 3) { mssql_os_workers_waiting_cpu_refresh; } +} + +sub mssql_fetch_callback +{ + my ($cluster, $item, $inst) = @_; + my ($value, @vfstats); + + #$pmda->log("mssql_fetch_callback $cluster:$item ($inst)\n"); + + if ($cluster == 0) { + if ($item > 6) { return (PM_ERR_PMID, 0); } + if ($inst < 0) { return (PM_ERR_INST, 0); } + if ($inst > @database_instances) { return (PM_ERR_INST, 0); } + $value = $virtual_file_stats[$inst]; + if (!defined($value)) { return (PM_ERR_INST, 0); } + @vfstats = @$value; + if (!defined($vfstats[$item+1])) { return (PM_ERR_AGAIN, 0); } + return ($vfstats[$item+1], 1); + } + if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } + if ($cluster == 1) { + if ($item > 3) { return (PM_ERR_PMID, 0); } + if (!defined($os_memory_clerks[$item])) { return (PM_ERR_AGAIN, 0); } + return ($os_memory_clerks[$item], 1); + } + if ($cluster == 2) { + if ($item > 0) { return (PM_ERR_PMID, 0); } + if (!defined($total_running_user_processes[$item])) { return (PM_ERR_AGAIN, 0); } + return ($total_running_user_processes[$item], 1); + } + if ($cluster == 3) { + if ($item > 0) { return (PM_ERR_PMID, 0); } + if (!defined($os_workers_waiting_cpu[$item])) { return (PM_ERR_AGAIN, 0); } + return ($os_workers_waiting_cpu[$item], 1); + } + return (PM_ERR_PMID, 0); +} + +$pmda = PCP::PMDA->new('mssql', 109); + +$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'mssql.virtual_file.read', 'Number of bytes reads issued on data file', ''); +$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'mssql.virtual_file.read_bytes', 'Total number of bytes read on the data file', ''); +$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), + 'mssql.virtual_file.read_io_stall_time', 'Total time in ms that the users waited for reads issued on the file', ''); +$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'mssql.virtual_file.write', 'Number of writes made on the data file', ''); +$pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'mssql.virtual_file.write_bytes', 'Total number of bytes written to the data file', ''); +$pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U64, $database_indom, + PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), + 'mssql.virtual_file.write_io_stall_time', 'Total time in ms that users waited for writes to be completed o the file', ''); +$pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U64, $database_indom, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'mssql.virtual_file.size', 'Number of bytes used on the disk from the data file', ''); + +$pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), + 'mssql.os_memory_clerks.bufferpool', '', ''); +$pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), + 'mssql.os_memory_clerks.querycompile', '', ''); +$pmda->add_metric(pmda_pmid(1,2), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), + 'mssql.os_memory_clerks.queryexec', '', ''); +$pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), + 'mssql.os_memory_clerks.queryplan', '', ''); + +$pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'mssql.running_user_process.total', 'Total number of running user process belonging to aconexsq', ''); + +$pmda->add_metric(pmda_pmid(3,0), PM_TYPE_U32, PM_INDOM_NULL, + PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'mssql.os_workers_waiting_cpu.count', 'Total number of queries waiting for cpu', ''); + +$pmda->add_indom($database_indom, \@database_instances, + 'Instance domain exporting each MSSQL database', ''); + +$pmda->set_fetch_callback(\&mssql_fetch_callback); +$pmda->set_fetch(\&mssql_connection_setup); +$pmda->set_refresh(\&mssql_refresh); +$pmda->run; + +=pod + +=head1 NAME + +pmdamssql - Microsoft SQL database PMDA + +=head1 DESCRIPTION + +B<pmdamssql> is a Performance Co-Pilot PMDA which extracts +live performance data from a running SQL Server database. +These metrics are typically sourced from Dynamic Management +Views (DMVs), augmenting the SQL server metrics exported by +the Windows PMDA. + +=head1 INSTALLATION + +B<pmdamssql> uses a configuration file from (in this order): + +=over + +=item * /etc/pcpdbi.conf + +=item * $PCP_PMDAS_DIR/mssql/mssql.conf + +=back + +This file can contain overridden values (Perl code) for the settings +listed at the start of pmdamssql.pl, namely: + +=over + +=item * database name (see DBI(3) for details) + +=item * database user name + +=item * database pass word + +=back + +Once this is setup, you can access the names and values for the +mysql performance metrics by doing the following as root: + + # cd $PCP_PMDAS_DIR/mssql + # ./Install + +If you want to undo the installation, do the following as root: + + # cd $PCP_PMDAS_DIR/mssql + # ./Remove + +B<pmdamssql> 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 /etc/pcpdbi.conf + +configuration file for all PCP database monitors + +=item $PCP_PMDAS_DIR/mssql/mssql.conf + +configuration file for B<pmdamssql> + +=item $PCP_PMDAS_DIR/mssql/Install + +installation script for the B<pmdamssql> agent + +=item $PCP_PMDAS_DIR/mssql/Remove + +undo installation script for the B<pmdamssql> agent + +=item $PCP_LOG_DIR/pmcd/mssql.log + +default log file for error messages from B<pmdamssql> + +=back + +=head1 SEE ALSO + +pmcd(1), pmdadbping.pl(1) and DBI(3). |