bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/sql_windows.go (about)

     1  package collectors
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"bosun.org/metadata"
     9  	"bosun.org/opentsdb"
    10  	"bosun.org/slog"
    11  	"bosun.org/util"
    12  	"github.com/StackExchange/wmi"
    13  )
    14  
    15  func init() {
    16  	c := &IntervalCollector{
    17  		F: c_mssql,
    18  	}
    19  	c.init = wmiInit(c, func() interface{} { return &[]Win32_Service{} }, wqlSQLInstanceFilter, &sqlQuery)
    20  	collectors = append(collectors, c)
    21  
    22  	var dstCluster []MSCluster_Cluster
    23  	q := wmi.CreateQuery(&dstCluster, ``)
    24  	if err := queryWmiNamespace(q, &dstCluster, rootMSCluster); err != nil {
    25  		sqlClusterName = "None"
    26  	} else if len(dstCluster) != 1 {
    27  		sqlClusterName = "Unknown"
    28  	} else {
    29  		sqlClusterName = dstCluster[0].Name
    30  	}
    31  
    32  	c_replica_db := &IntervalCollector{
    33  		F: c_mssql_replica_db,
    34  	}
    35  	c_replica_db.init = wmiInit(c_replica_db, func() interface{} { return &[]Win32_PerfRawData_MSSQLSERVER_SQLServerDatabaseReplica{} }, `WHERE Name <> '_Total'`, &sqlAGDBQuery)
    36  	collectors = append(collectors, c_replica_db)
    37  
    38  	c_replica_server := &IntervalCollector{
    39  		F: c_mssql_replica_server,
    40  	}
    41  	c_replica_server.init = wmiInit(c_replica_server, func() interface{} { return &[]Win32_PerfRawData_MSSQLSERVER_SQLServerAvailabilityReplica{} }, `WHERE Name <> '_Total'`, &sqlAGQuery)
    42  	collectors = append(collectors, c_replica_server)
    43  
    44  	c_replica_votes := &IntervalCollector{
    45  		F:        c_mssql_replica_votes,
    46  		Interval: time.Minute * 5,
    47  	}
    48  	c_replica_votes.init = wmiInitNamespace(c_replica_votes, func() interface{} { return &[]MSCluster_Node{} }, fmt.Sprintf("WHERE Name = '%s'", util.GetHostManager().GetHostName()), &sqlAGVotes, rootMSCluster)
    49  	collectors = append(collectors, c_replica_votes)
    50  
    51  	c_replica_resources := &IntervalCollector{
    52  		F:        c_mssql_replica_resources,
    53  		Interval: time.Minute,
    54  	}
    55  	c_replica_resources.init = wmiInitNamespace(c_replica_resources, func() interface{} { return &[]MSCluster_Resource{} }, ``, &sqlAGResources, rootMSCluster)
    56  	collectors = append(collectors, c_replica_resources)
    57  }
    58  
    59  const (
    60  	rootMSCluster        string = "root\\MSCluster"
    61  	wqlSQLInstanceFilter string = `WHERE (Name Like 'MSSQL$%' or Name = 'MSSQLSERVER') and not (Name Like 'MSSQL$MICROSOFT##%' or StartMode = 'Disabled')`
    62  )
    63  
    64  var (
    65  	sqlClusterName string
    66  	sqlQuery       string
    67  	sqlAGDBQuery   string
    68  	sqlAGQuery     string
    69  	sqlAGVotes     string
    70  	sqlAGResources string
    71  )
    72  
    73  func c_mssql() (opentsdb.MultiDataPoint, error) {
    74  	var err error
    75  	var svc_dst []Win32_Service
    76  	var svc_q = wmi.CreateQuery(&svc_dst, wqlSQLInstanceFilter)
    77  	err = queryWmi(svc_q, &svc_dst)
    78  	if err != nil {
    79  		return nil, slog.Wrap(err)
    80  	}
    81  	var md opentsdb.MultiDataPoint
    82  	add := func(f func([]Win32_Service) (opentsdb.MultiDataPoint, error)) {
    83  		dps, e := f(svc_dst)
    84  		if e != nil {
    85  			err = e
    86  		}
    87  		md = append(md, dps...)
    88  	}
    89  	add(c_mssql_general)
    90  	add(c_mssql_statistics)
    91  	add(c_mssql_locks)
    92  	add(c_mssql_databases)
    93  	add(c_mssql_memory)
    94  	add(c_mssql_buffer)
    95  	return md, err
    96  }
    97  
    98  func c_mssql_general(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
    99  	var md opentsdb.MultiDataPoint
   100  	for _, w := range svc_dst {
   101  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerGeneralStatistics
   102  		q := wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
   103  		label := "mssqlserver"
   104  		if w.Name != `MSSQLSERVER` {
   105  			q = instanceWMIQuery(w.Name, q)
   106  			label = strings.ToLower(w.Name[6:len(w.Name)])
   107  		}
   108  		if err := queryWmi(q, &dst); err != nil {
   109  			return nil, slog.Wrap(err)
   110  		}
   111  		for _, v := range dst {
   112  			tags := opentsdb.TagSet{"instance": label}
   113  			Add(&md, "mssql.user_connections", v.UserConnections, tags, metadata.Gauge, metadata.Count, descMSSQLUserConnections)
   114  			Add(&md, "mssql.connection_resets", v.ConnectionResetPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLConnectionResetPersec)
   115  			Add(&md, "mssql.logins", v.LoginsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLoginsPersec)
   116  			Add(&md, "mssql.logouts", v.LogoutsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogoutsPersec)
   117  			Add(&md, "mssql.mars_deadlocks", v.MarsDeadlocks, tags, metadata.Counter, metadata.Count, descMSSQLMarsDeadlocks)
   118  			Add(&md, "mssql.proc_blocked", v.Processesblocked, tags, metadata.Gauge, metadata.Count, descMSSQLProcessesblocked)
   119  			Add(&md, "mssql.temptables_created", v.TempTablesCreationRate, tags, metadata.Counter, metadata.PerSecond, descMSSQLTempTablesCreationRate)
   120  			Add(&md, "mssql.temptables_to_destroy", v.TempTablesForDestruction, tags, metadata.Gauge, metadata.Count, descMSSQLTempTablesForDestruction)
   121  			Add(&md, "mssql.transactions_total", v.Transactions, tags, metadata.Gauge, metadata.Count, descMSSQLTransactions)
   122  
   123  		}
   124  	}
   125  	return md, nil
   126  }
   127  
   128  const (
   129  	descMSSQLUserConnections          = "Number of users connected to the system."
   130  	descMSSQLConnectionResetPersec    = "Total number of connection resets per second."
   131  	descMSSQLLoginsPersec             = "Total number of logins started per second."
   132  	descMSSQLLogoutsPersec            = "Total number of logouts started per second."
   133  	descMSSQLMarsDeadlocks            = "Number of Mars Deadlocks detected."
   134  	descMSSQLProcessesblocked         = "Number of currently blocked processes."
   135  	descMSSQLTempTablesCreationRate   = "Number of temporary tables/table variables created/sec."
   136  	descMSSQLTempTablesForDestruction = "Number of temporary tables/table variables waiting to be destroyed by the cleanup system thread."
   137  	descMSSQLTransactions             = "Number of transaction enlistments (local, dtc, and bound)."
   138  )
   139  
   140  type Win32_PerfRawData_MSSQLSERVER_SQLServerGeneralStatistics struct {
   141  	ConnectionResetPersec    uint64
   142  	LoginsPersec             uint64
   143  	LogoutsPersec            uint64
   144  	MarsDeadlocks            uint64
   145  	Processesblocked         uint64
   146  	TempTablesCreationRate   uint64
   147  	TempTablesForDestruction uint64
   148  	Transactions             uint64
   149  	UserConnections          uint64
   150  }
   151  
   152  func c_mssql_statistics(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
   153  	var md opentsdb.MultiDataPoint
   154  	for _, w := range svc_dst {
   155  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerSQLStatistics
   156  		q := wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
   157  		label := "mssqlserver"
   158  		if w.Name != `MSSQLSERVER` {
   159  			q = instanceWMIQuery(w.Name, q)
   160  			label = strings.ToLower(w.Name[6:len(w.Name)])
   161  		}
   162  		err := queryWmi(q, &dst)
   163  		if err != nil {
   164  			return nil, slog.Wrap(err)
   165  		}
   166  		for _, v := range dst {
   167  			tags := opentsdb.TagSet{"instance": label}
   168  			Add(&md, "mssql.autoparam_attempts", v.AutoParamAttemptsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLAutoParamAttemptsPersec)
   169  			Add(&md, "mssql.autoparam_failed", v.FailedAutoParamsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLFailedAutoParamsPersec)
   170  			Add(&md, "mssql.autoparam_forced", v.ForcedParameterizationsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLForcedParameterizationsPersec)
   171  			Add(&md, "mssql.autoparam_safe", v.SafeAutoParamsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLSafeAutoParamsPersec)
   172  			Add(&md, "mssql.autoparam_unsafe", v.UnsafeAutoParamsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLUnsafeAutoParamsPersec)
   173  			Add(&md, "mssql.batches", v.BatchRequestsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLBatchRequestsPersec)
   174  			Add(&md, "mssql.guided_plans", v.GuidedplanexecutionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLGuidedplanexecutionsPersec)
   175  			Add(&md, "mssql.misguided_plans", v.MisguidedplanexecutionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLMisguidedplanexecutionsPersec)
   176  			Add(&md, "mssql.compilations", v.SQLCompilationsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLSQLCompilationsPersec)
   177  			Add(&md, "mssql.recompilations", v.SQLReCompilationsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLSQLReCompilationsPersec)
   178  		}
   179  	}
   180  	return md, nil
   181  }
   182  
   183  const (
   184  	descMSSQLAutoParamAttemptsPersec       = "Number of auto-parameterization attempts."
   185  	descMSSQLFailedAutoParamsPersec        = "Number of failed auto-parameterizations."
   186  	descMSSQLForcedParameterizationsPersec = "Number of statements parameterized by forced parameterization per second."
   187  	descMSSQLSafeAutoParamsPersec          = "Number of safe auto-parameterizations."
   188  	descMSSQLUnsafeAutoParamsPersec        = "Number of unsafe auto-parameterizations."
   189  	descMSSQLBatchRequestsPersec           = "Number of SQL batch requests received by server."
   190  	descMSSQLGuidedplanexecutionsPersec    = "Number of plan executions per second in which the query plan has been generated by using a plan guide."
   191  	descMSSQLMisguidedplanexecutionsPersec = "Number of plan executions per second in which a plan guide could not be honored during plan generation. The plan guide was disregarded and normal compilation was used to generate the executed plan."
   192  	descMSSQLSQLCompilationsPersec         = "Number of SQL compilations."
   193  	descMSSQLSQLReCompilationsPersec       = "Number of SQL re-compiles."
   194  )
   195  
   196  type Win32_PerfRawData_MSSQLSERVER_SQLServerSQLStatistics struct {
   197  	AutoParamAttemptsPersec       uint64
   198  	BatchRequestsPersec           uint64
   199  	FailedAutoParamsPersec        uint64
   200  	ForcedParameterizationsPersec uint64
   201  	GuidedplanexecutionsPersec    uint64
   202  	MisguidedplanexecutionsPersec uint64
   203  	SafeAutoParamsPersec          uint64
   204  	SQLCompilationsPersec         uint64
   205  	SQLReCompilationsPersec       uint64
   206  	UnsafeAutoParamsPersec        uint64
   207  }
   208  
   209  func c_mssql_locks(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
   210  	var md opentsdb.MultiDataPoint
   211  	for _, w := range svc_dst {
   212  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerLocks
   213  		q := wmi.CreateQuery(&dst, `WHERE Name = 'Page' OR Name = 'Extent' OR Name = 'Object' or Name = 'Database'`)
   214  		label := "mssqlserver"
   215  		if w.Name != `MSSQLSERVER` {
   216  			q = instanceWMIQuery(w.Name, q)
   217  			label = strings.ToLower(w.Name[6:len(w.Name)])
   218  		}
   219  		err := queryWmi(q, &dst)
   220  		if err != nil {
   221  			return nil, slog.Wrap(err)
   222  		}
   223  		for _, v := range dst {
   224  			tags := opentsdb.TagSet{"instance": label, "type": v.Name}
   225  			Add(&md, "mssql.lock_wait_time", v.AverageWaitTimems, tags, metadata.Counter, metadata.MilliSecond, descMSSQLAverageWaitTimems)
   226  			Add(&md, "mssql.lock_requests", v.LockRequestsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLockRequestsPersec)
   227  			Add(&md, "mssql.lock_timeouts", v.LockTimeoutsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLockTimeoutsPersec)
   228  			Add(&md, "mssql.lock_timeouts0", v.LockTimeoutstimeout0Persec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLockTimeoutstimeout0Persec)
   229  			Add(&md, "mssql.lock_waits", v.LockWaitsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLockWaitsPersec)
   230  			Add(&md, "mssql.deadlocks", v.NumberofDeadlocksPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLNumberofDeadlocksPersec)
   231  		}
   232  	}
   233  	return md, nil
   234  }
   235  
   236  const (
   237  	descMSSQLAverageWaitTimems          = "The average amount of wait time (milliseconds) for each lock request that resulted in a wait."
   238  	descMSSQLLockRequestsPersec         = "Number of new locks and lock conversions requested from the lock manager."
   239  	descMSSQLLockTimeoutsPersec         = "Number of lock requests that timed out. This includes requests for NOWAIT locks."
   240  	descMSSQLLockTimeoutstimeout0Persec = "Number of lock requests that timed out. This does not include requests for NOWAIT locks."
   241  	descMSSQLLockWaitsPersec            = "Number of lock requests that could not be satisfied immediately and required the caller to wait before being granted the lock."
   242  	descMSSQLNumberofDeadlocksPersec    = "Number of lock requests that resulted in a deadlock."
   243  )
   244  
   245  type Win32_PerfRawData_MSSQLSERVER_SQLServerLocks struct {
   246  	AverageWaitTimems          uint64
   247  	LockRequestsPersec         uint64
   248  	LockTimeoutsPersec         uint64
   249  	LockTimeoutstimeout0Persec uint64
   250  	LockWaitsPersec            uint64
   251  	Name                       string
   252  	NumberofDeadlocksPersec    uint64
   253  }
   254  
   255  func c_mssql_databases(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
   256  	var md opentsdb.MultiDataPoint
   257  	for _, w := range svc_dst {
   258  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerDatabases
   259  		q := wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
   260  		label := "mssqlserver"
   261  		if w.Name != `MSSQLSERVER` {
   262  			q = instanceWMIQuery(w.Name, q)
   263  			label = strings.ToLower(w.Name[6:len(w.Name)])
   264  		}
   265  		err := queryWmi(q, &dst)
   266  		if err != nil {
   267  			return nil, slog.Wrap(err)
   268  		}
   269  		for _, v := range dst {
   270  			tags := opentsdb.TagSet{"instance": label, "db": v.Name}
   271  			Add(&md, "mssql.active_transactions", v.ActiveTransactions, tags, metadata.Gauge, metadata.Count, descMSSQLActiveTransactions)
   272  			Add(&md, "mssql.backup_restore_throughput", v.BackupPerRestoreThroughputPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLBackupPerRestoreThroughputPersec)
   273  			Add(&md, "mssql.bulkcopy_rows", v.BulkCopyRowsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLBulkCopyRowsPersec)
   274  			Add(&md, "mssql.bulkcopy_throughput", v.BulkCopyThroughputPersec, tags, metadata.Counter, metadata.KBytes, descMSSQLBulkCopyThroughputPersec)
   275  			Add(&md, "mssql.commit_table_entries", v.Committableentries, tags, metadata.Gauge, metadata.Count, descMSSQLCommittableentries)
   276  			Add(&md, "mssql.data_files_size", v.DataFilesSizeKB*1024, tags, metadata.Gauge, metadata.Bytes, descMSSQLDataFilesSizeKB)
   277  			Add(&md, "mssql.dbcc_logical_scan_bytes", v.DBCCLogicalScanBytesPersec, tags, metadata.Counter, metadata.BytesPerSecond, descMSSQLDBCCLogicalScanBytesPersec)
   278  			//Add(&md, "mssql.group_commit_time", v.GroupCommitTimePersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLGroupCommitTimePersec)
   279  			Add(&md, "mssql.log_bytes_flushed", v.LogBytesFlushedPersec, tags, metadata.Counter, metadata.BytesPerSecond, descMSSQLLogBytesFlushedPersec)
   280  			Add(&md, "mssql.log_cache_hit_ratio", v.LogCacheHitRatio, tags, metadata.Counter, metadata.Pct, descMSSQLLogCacheHitRatio)
   281  			Add(&md, "mssql.log_cache_hit_ratio_base", v.LogCacheHitRatio_Base, tags, metadata.Counter, metadata.None, descMSSQLLogCacheHitRatio_Base)
   282  			Add(&md, "mssql.log_cache_reads", v.LogCacheReadsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogCacheReadsPersec)
   283  			Add(&md, "mssql.log_files_size", v.LogFilesSizeKB*1024, tags, metadata.Gauge, metadata.Bytes, descMSSQLLogFilesSizeKB)
   284  			Add(&md, "mssql.log_files_used_size", v.LogFilesUsedSizeKB*1024, tags, metadata.Gauge, metadata.Bytes, descMSSQLLogFilesUsedSizeKB)
   285  			Add(&md, "mssql.log_flushes", v.LogFlushesPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogFlushesPersec)
   286  			Add(&md, "mssql.log_flush_waits", v.LogFlushWaitsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogFlushWaitsPersec)
   287  			Add(&md, "mssql.log_flush_wait_time", v.LogFlushWaitTime, tags, metadata.Counter, metadata.MilliSecond, descMSSQLLogFlushWaitTime)
   288  			//Add(&md, "mssql.log_flush_write_time_ms", v.LogFlushWriteTimems, tags, metadata.Counter, metadata.MilliSecond, descMSSQLLogFlushWriteTimems)
   289  			Add(&md, "mssql.log_growths", v.LogGrowths, tags, metadata.Gauge, metadata.Count, descMSSQLLogGrowths)
   290  			//Add(&md, "mssql.log_pool_cache_misses", v.LogPoolCacheMissesPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogPoolCacheMissesPersec)
   291  			//Add(&md, "mssql.log_pool_disk_reads", v.LogPoolDiskReadsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogPoolDiskReadsPersec)
   292  			//Add(&md, "mssql.log_pool_requests", v.LogPoolRequestsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLLogPoolRequestsPersec)
   293  			Add(&md, "mssql.log_shrinks", v.LogShrinks, tags, metadata.Gauge, metadata.Count, descMSSQLLogShrinks)
   294  			Add(&md, "mssql.log_truncations", v.LogTruncations, tags, metadata.Gauge, metadata.Count, descMSSQLLogTruncations)
   295  			Add(&md, "mssql.percent_log_used", v.PercentLogUsed, tags, metadata.Gauge, metadata.Pct, descMSSQLPercentLogUsed)
   296  			Add(&md, "mssql.repl_pending_xacts", v.ReplPendingXacts, tags, metadata.Gauge, metadata.Count, descMSSQLReplPendingXacts)
   297  			Add(&md, "mssql.repl_trans_rate", v.ReplTransRate, tags, metadata.Counter, metadata.PerSecond, descMSSQLReplTransRate)
   298  			Add(&md, "mssql.shrink_data_movement_bytes", v.ShrinkDataMovementBytesPersec, tags, metadata.Counter, metadata.BytesPerSecond, descMSSQLShrinkDataMovementBytesPersec)
   299  			Add(&md, "mssql.tracked_transactions", v.TrackedtransactionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLTrackedtransactionsPersec)
   300  			Add(&md, "mssql.transactions", v.TransactionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLTransactionsPersec)
   301  			Add(&md, "mssql.write_transactions", v.WriteTransactionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLWriteTransactionsPersec)
   302  		}
   303  	}
   304  	return md, nil
   305  }
   306  
   307  const (
   308  	descMSSQLActiveTransactions               = "Number of active update transactions for the database."
   309  	descMSSQLBackupPerRestoreThroughputPersec = "Read/write throughput for backup/restore of a database."
   310  	descMSSQLBulkCopyRowsPersec               = "Number of rows bulk copied."
   311  	descMSSQLBulkCopyThroughputPersec         = "KiloBytes bulk copied."
   312  	descMSSQLCommittableentries               = "The size of the in-memory part of the commit table for the database."
   313  	descMSSQLDataFilesSizeKB                  = "The cumulative size of all the data files in the database."
   314  	descMSSQLDBCCLogicalScanBytesPersec       = "Logical read scan rate for DBCC commands."
   315  	descMSSQLGroupCommitTimePersec            = "Group stall time (microseconds) per second."
   316  	descMSSQLLogBytesFlushedPersec            = "Total number of log bytes flushed."
   317  	descMSSQLLogCacheHitRatio                 = "Percentage of log cache reads that were satisfied from the log cache."
   318  	descMSSQLLogCacheHitRatio_Base            = "Percentage of log cache reads that were satisfied from the log cache."
   319  	descMSSQLLogCacheReadsPersec              = "Reads performed through the log manager cache."
   320  	descMSSQLLogFilesSizeKB                   = "The cumulative size of all the log files in the database."
   321  	descMSSQLLogFilesUsedSizeKB               = "The cumulative used size of all the log files in the database."
   322  	descMSSQLLogFlushesPersec                 = "Number of log flushes."
   323  	descMSSQLLogFlushWaitsPersec              = "Number of commits waiting on log flush."
   324  	descMSSQLLogFlushWaitTime                 = "Total wait time (milliseconds)."
   325  	descMSSQLLogFlushWriteTimems              = "Milliseconds it took to perform the writes of log flushes completed in the last second."
   326  	descMSSQLLogGrowths                       = "Total number of log growths for this database."
   327  	descMSSQLLogPoolCacheMissesPersec         = "Log block cache misses from log pool."
   328  	descMSSQLLogPoolDiskReadsPersec           = "Log disk reads via log pool."
   329  	descMSSQLLogPoolRequestsPersec            = "Log block requests performed through log pool."
   330  	descMSSQLLogShrinks                       = "Total number of log shrinks for this database."
   331  	descMSSQLLogTruncations                   = "Total number of log truncations for this database."
   332  	descMSSQLPercentLogUsed                   = "The percent of space in the log that is in use."
   333  	descMSSQLReplPendingXacts                 = "Number of pending replication transactions in the database."
   334  	descMSSQLReplTransRate                    = "Replication transaction rate (replicated transactions/sec.)."
   335  	descMSSQLShrinkDataMovementBytesPersec    = "The rate data is being moved by Autoshrink, DBCC SHRINKDATABASE or SHRINKFILE."
   336  	descMSSQLTrackedtransactionsPersec        = "Number of committed transactions recorded in the commit table for the database."
   337  	descMSSQLTransactionsPersec               = "Number of transactions started for the database."
   338  	descMSSQLWriteTransactionsPersec          = "Number of transactions which wrote to the database in the last second."
   339  )
   340  
   341  type Win32_PerfRawData_MSSQLSERVER_SQLServerDatabases struct {
   342  	ActiveTransactions               uint64
   343  	BackupPerRestoreThroughputPersec uint64
   344  	BulkCopyRowsPersec               uint64
   345  	BulkCopyThroughputPersec         uint64
   346  	Committableentries               uint64
   347  	DataFilesSizeKB                  uint64
   348  	DBCCLogicalScanBytesPersec       uint64
   349  	//GroupCommitTimePersec            uint64
   350  	LogBytesFlushedPersec uint64
   351  	LogCacheHitRatio      uint64
   352  	LogCacheHitRatio_Base uint64
   353  	LogCacheReadsPersec   uint64
   354  	LogFilesSizeKB        uint64
   355  	LogFilesUsedSizeKB    uint64
   356  	LogFlushesPersec      uint64
   357  	LogFlushWaitsPersec   uint64
   358  	LogFlushWaitTime      uint64
   359  	//LogFlushWriteTimems              uint64
   360  	LogGrowths uint64
   361  	//LogPoolCacheMissesPersec         uint64
   362  	//LogPoolDiskReadsPersec uint64
   363  	//LogPoolRequestsPersec            uint64
   364  	LogShrinks                    uint64
   365  	LogTruncations                uint64
   366  	Name                          string
   367  	PercentLogUsed                uint64
   368  	ReplPendingXacts              uint64
   369  	ReplTransRate                 uint64
   370  	ShrinkDataMovementBytesPersec uint64
   371  	TrackedtransactionsPersec     uint64
   372  	TransactionsPersec            uint64
   373  	WriteTransactionsPersec       uint64
   374  }
   375  
   376  func c_mssql_replica_db() (opentsdb.MultiDataPoint, error) {
   377  	var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerDatabaseReplica
   378  	if err := queryWmi(sqlAGDBQuery, &dst); err != nil {
   379  		return nil, slog.Wrap(err)
   380  	}
   381  	var md opentsdb.MultiDataPoint
   382  	for _, v := range dst {
   383  		tags := opentsdb.TagSet{"db": v.Name}
   384  		//see http://technet.microsoft.com/en-us/library/dn135338%28v=sql.110%29.aspx
   385  		Add(&md, "mssql.replica.bytes_db", v.FileBytesReceivedPersec, opentsdb.TagSet{"db": v.Name, "type": "filestream_received"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaFileBytesReceivedPersec)
   386  		Add(&md, "mssql.replica.bytes_db", v.LogBytesReceivedPersec, opentsdb.TagSet{"db": v.Name, "type": "log_received"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaLogBytesReceivedPersec)
   387  		Add(&md, "mssql.replica.bytes_db", v.RedoneBytesPersec, opentsdb.TagSet{"db": v.Name, "type": "log_redone"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaRedoneBytesPersec)
   388  		Add(&md, "mssql.replica.mirrored_transactions", v.MirroredWriteTransactionsPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLReplicaMirroredWriteTransactionsPersec)
   389  		Add(&md, "mssql.replica.redo_blocked", v.RedoblockedPersec, tags, metadata.Counter, metadata.PerSecond, descMSSQLReplicaRedoblockedPersec)
   390  		Add(&md, "mssql.replica.delay_ack", v.TransactionDelay, opentsdb.TagSet{"db": v.Name}, metadata.Counter, metadata.MilliSecond, descMSSQLReplicaTransactionDelay)
   391  		Add(&md, "mssql.replica.recovery", v.LogSendQueue*1024, opentsdb.TagSet{"db": v.Name, "type": "sending"}, metadata.Gauge, metadata.Bytes, descMSSQLReplicaLogSendQueue)
   392  		Add(&md, "mssql.replica.recovery", v.RecoveryQueue*1024, opentsdb.TagSet{"db": v.Name, "type": "received"}, metadata.Gauge, metadata.Bytes, descMSSQLReplicaRecoveryQueue)
   393  		Add(&md, "mssql.replica.recovery", v.RedoBytesRemaining*1024, opentsdb.TagSet{"db": v.Name, "type": "redo"}, metadata.Gauge, metadata.Bytes, descMSSQLReplicaRedoBytesRemaining)
   394  		Add(&md, "mssql.replica.recovery", v.TotalLogrequiringundo*1024, opentsdb.TagSet{"db": v.Name, "type": "undo_total"}, metadata.Gauge, metadata.Bytes, descMSSQLReplicaTotalLogrequiringundo)
   395  		Add(&md, "mssql.replica.recovery", v.Logremainingforundo*1024, opentsdb.TagSet{"db": v.Name, "type": "undo_remaining"}, metadata.Gauge, metadata.Bytes, descMSSQLReplicaLogremainingforundo)
   396  	}
   397  	return md, nil
   398  }
   399  
   400  const (
   401  	descMSSQLReplicaFileBytesReceivedPersec         = "Amount of filestream data received by the availability replica for the database."
   402  	descMSSQLReplicaLogBytesReceivedPersec          = "Amount of logs received by the availability replica for the database."
   403  	descMSSQLReplicaLogremainingforundo             = "The amount of log in bytes remaining to finish the undo phase."
   404  	descMSSQLReplicaLogSendQueue                    = "Amount of logs in bytes that is waiting to be sent to the database replica."
   405  	descMSSQLReplicaMirroredWriteTransactionsPersec = "Number of transactions which wrote to the mirrored database in the last second, that waited for log to be sent to the mirror."
   406  	descMSSQLReplicaRecoveryQueue                   = "Total number of hardened log in bytes that is waiting to be redone on the secondary."
   407  	descMSSQLReplicaRedoblockedPersec               = "Number of times redo gets blocked in the last second."
   408  	descMSSQLReplicaRedoBytesRemaining              = "The amount of log in bytes remaining to be redone to finish the reverting phase."
   409  	descMSSQLReplicaRedoneBytesPersec               = "Amount of log records redone in the last second to catch up the database replica."
   410  	descMSSQLReplicaTotalLogrequiringundo           = "The amount of log in bytes that need to be undone."
   411  	descMSSQLReplicaTransactionDelay                = "Number of milliseconds transaction termination waited for acknowledgement per second."
   412  )
   413  
   414  type Win32_PerfRawData_MSSQLSERVER_SQLServerDatabaseReplica struct {
   415  	FileBytesReceivedPersec         uint64
   416  	LogBytesReceivedPersec          uint64
   417  	Logremainingforundo             uint64
   418  	LogSendQueue                    uint64
   419  	MirroredWriteTransactionsPersec uint64
   420  	Name                            string
   421  	RecoveryQueue                   uint64
   422  	RedoblockedPersec               uint64
   423  	RedoBytesRemaining              uint64
   424  	RedoneBytesPersec               uint64
   425  	TotalLogrequiringundo           uint64
   426  	TransactionDelay                uint64
   427  }
   428  
   429  func c_mssql_replica_server() (opentsdb.MultiDataPoint, error) {
   430  	var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerAvailabilityReplica
   431  	if err := queryWmi(sqlAGQuery, &dst); err != nil {
   432  		return nil, slog.Wrap(err)
   433  	}
   434  	var md opentsdb.MultiDataPoint
   435  	for _, v := range dst {
   436  		//split name into AvailibilityGroup and Destination. Name is in 'Group:Destination' format
   437  		s := strings.Split(v.Name, ":")
   438  		if len(s) != 2 {
   439  			return nil, fmt.Errorf("Invalid Availibility Group Name: '%s'", v.Name)
   440  		}
   441  		destination := strings.ToLower(s[1])
   442  		//see http://technet.microsoft.com/en-us/library/ff878472(v=sql.110).aspx
   443  		//also https://livedemo.customers.na.apm.ibmserviceengage.com/help/index.jsp?topic=%2Fcom.ibm.koq.doc%2Fattr_koqadbst.htm
   444  		Add(&md, "mssql.replica.bytes_ag", v.BytesReceivedfromReplicaPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "received"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaBytesReceivedfromReplicaPersec)
   445  		Add(&md, "mssql.replica.bytes_ag", v.BytesSenttoReplicaPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "sent_replica"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaBytesSenttoReplicaPersec)
   446  		Add(&md, "mssql.replica.bytes_ag", v.BytesSenttoTransportPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "sent_transport"}, metadata.Counter, metadata.BytesPerSecond, descMSSQLReplicaBytesSenttoTransportPersec)
   447  		Add(&md, "mssql.replica.delay_flow", v.FlowControlTimemsPersec, opentsdb.TagSet{"group": s[0], "destination": destination}, metadata.Counter, metadata.MilliSecond, descMSSQLReplicaFlowControlTimemsPersec)
   448  		Add(&md, "mssql.replica.messages", v.FlowControlPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "flow_control"}, metadata.Counter, metadata.PerSecond, descMSSQLReplicaFlowControlPersec)
   449  		Add(&md, "mssql.replica.messages", v.ReceivesfromReplicaPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "received"}, metadata.Counter, metadata.PerSecond, descMSSQLReplicaReceivesfromReplicaPersec)
   450  		Add(&md, "mssql.replica.messages", v.ResentMessagesPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "resent"}, metadata.Counter, metadata.PerSecond, descMSSQLReplicaResentMessagesPersec)
   451  		Add(&md, "mssql.replica.messages", v.SendstoReplicaPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "sent_replica"}, metadata.Counter, metadata.PerSecond, descMSSQLReplicaSendstoReplicaPersec)
   452  		Add(&md, "mssql.replica.messages", v.SendstoTransportPersec, opentsdb.TagSet{"group": s[0], "destination": destination, "type": "sent_transport"}, metadata.Counter, metadata.PerSecond, descMSSQLReplicaSendstoTransportPersec)
   453  
   454  	}
   455  	return md, nil
   456  }
   457  
   458  const (
   459  	descMSSQLReplicaBytesReceivedfromReplicaPersec = "Total bytes receieved from the availability replica."
   460  	descMSSQLReplicaBytesSenttoReplicaPersec       = "Total bytes sent to the availabilty replica."
   461  	descMSSQLReplicaBytesSenttoTransportPersec     = "Total bytes sent to transport for the availabilty replica."
   462  	descMSSQLReplicaFlowControlPersec              = "Number of flow control initiated in the last second."
   463  	descMSSQLReplicaFlowControlTimemsPersec        = "Time in milliseconds messages waited on flow control in the last second."
   464  	descMSSQLReplicaReceivesfromReplicaPersec      = "Total receives from the availability replica."
   465  	descMSSQLReplicaResentMessagesPersec           = "Number of messages being resent in the last second."
   466  	descMSSQLReplicaSendstoReplicaPersec           = "Total sends to the availability replica."
   467  	descMSSQLReplicaSendstoTransportPersec         = "Total sends to transport for the availability replica."
   468  )
   469  
   470  type Win32_PerfRawData_MSSQLSERVER_SQLServerAvailabilityReplica struct {
   471  	BytesReceivedfromReplicaPersec uint64
   472  	BytesSenttoReplicaPersec       uint64
   473  	BytesSenttoTransportPersec     uint64
   474  	FlowControlPersec              uint64
   475  	FlowControlTimemsPersec        uint64
   476  	Name                           string
   477  	ReceivesfromReplicaPersec      uint64
   478  	ResentMessagesPersec           uint64
   479  	SendstoReplicaPersec           uint64
   480  	SendstoTransportPersec         uint64
   481  }
   482  
   483  func c_mssql_replica_votes() (opentsdb.MultiDataPoint, error) {
   484  	var dst []MSCluster_Node
   485  	if err := queryWmiNamespace(sqlAGVotes, &dst, rootMSCluster); err != nil {
   486  		return nil, slog.Wrap(err)
   487  	}
   488  
   489  	var md opentsdb.MultiDataPoint
   490  	for _, v := range dst {
   491  		Add(&md, "mssql.replica.votes", v.NodeWeight, opentsdb.TagSet{"cluster": sqlClusterName, "type": "standard"}, metadata.Gauge, metadata.Count, descMSSQLReplicaNodeWeight)
   492  		Add(&md, "mssql.replica.votes", v.DynamicWeight, opentsdb.TagSet{"cluster": sqlClusterName, "type": "dynamic"}, metadata.Gauge, metadata.Count, descMSSQLReplicaDynamicWeight)
   493  		Add(&md, "mssql.replica.cluster_state", v.State, opentsdb.TagSet{"cluster": sqlClusterName}, metadata.Gauge, metadata.StatusCode, descMSSQLReplicaClusterState)
   494  	}
   495  	return md, nil
   496  }
   497  
   498  const (
   499  	descMSSQLReplicaNodeWeight    = "The current vote weight of the node."
   500  	descMSSQLReplicaDynamicWeight = "The vote weight of the node when adjusted by the dynamic quorum feature."
   501  	descMSSQLReplicaClusterState  = "StateUnknown (-1), Up (0), Down (1), Paused (2), Joining (3)."
   502  )
   503  
   504  type MSCluster_Node struct {
   505  	Name          string
   506  	NodeWeight    uint32
   507  	DynamicWeight uint32
   508  	State         uint32
   509  }
   510  
   511  type MSCluster_Cluster struct {
   512  	Name string
   513  }
   514  
   515  func c_mssql_replica_resources() (opentsdb.MultiDataPoint, error) {
   516  	var dst []MSCluster_Resource
   517  	//Only report metrics for resources owned by this node
   518  	q := wmi.CreateQuery(&dst, fmt.Sprintf("WHERE OwnerNode = '%s'", util.GetHostManager().GetHostName()))
   519  	if err := queryWmiNamespace(q, &dst, rootMSCluster); err != nil {
   520  		return nil, slog.Wrap(err)
   521  	}
   522  	var md opentsdb.MultiDataPoint
   523  	for _, v := range dst {
   524  		Add(&md, "mssql.replica.resource_state", v.State, opentsdb.TagSet{"group": v.OwnerGroup, "type": v.Type, "name": v.Name}, metadata.Gauge, metadata.StatusCode, descMSSQLReplicaResourceState)
   525  	}
   526  	return md, nil
   527  }
   528  
   529  const (
   530  	descMSSQLReplicaResourceState = "StateUnknown (-1), TBD (0), Initializing (1), Online (2), Offline (3), Failed(4), Pending(128), Online Pending (129), Offline Pending (130)."
   531  )
   532  
   533  type MSCluster_Resource struct {
   534  	Name       string
   535  	OwnerGroup string
   536  	OwnerNode  string
   537  	Type       string
   538  	State      uint32
   539  }
   540  
   541  func c_mssql_memory(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
   542  	var md opentsdb.MultiDataPoint
   543  	for _, w := range svc_dst {
   544  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerMemoryManager
   545  		q := wmi.CreateQuery(&dst, ``)
   546  		label := "mssqlserver"
   547  		if w.Name != `MSSQLSERVER` {
   548  			q = instanceWMIQuery(w.Name, q)
   549  			label = strings.ToLower(w.Name[6:len(w.Name)])
   550  		}
   551  		if err := queryWmi(q, &dst); err != nil {
   552  			return nil, slog.Wrap(err)
   553  		}
   554  		for _, v := range dst {
   555  			tags := opentsdb.TagSet{"instance": label}
   556  			Add(&md, "mssql.memory.target", v.TargetServerMemoryKB*1024, tags, metadata.Gauge, metadata.Bytes, descMSSQLTargetServerMemoryKB)
   557  			Add(&md, "mssql.memory.total", v.TotalServerMemoryKB*1024, tags, metadata.Gauge, metadata.Bytes, descMSSQLTotalServerMemoryKB)
   558  		}
   559  	}
   560  	return md, nil
   561  }
   562  
   563  const (
   564  	descMSSQLTargetServerMemoryKB = "Indicates the ideal amount of memory the server can consume."
   565  	descMSSQLTotalServerMemoryKB  = "Specifies the amount of memory the server has committed using the memory manager."
   566  )
   567  
   568  type Win32_PerfRawData_MSSQLSERVER_SQLServerMemoryManager struct {
   569  	TargetServerMemoryKB uint64
   570  	TotalServerMemoryKB  uint64
   571  }
   572  
   573  func c_mssql_buffer(svc_dst []Win32_Service) (opentsdb.MultiDataPoint, error) {
   574  	var md opentsdb.MultiDataPoint
   575  	for _, w := range svc_dst {
   576  		var dst []Win32_PerfRawData_MSSQLSERVER_SQLServerBufferManager
   577  		q := wmi.CreateQuery(&dst, ``)
   578  		label := "mssqlserver"
   579  		if w.Name != `MSSQLSERVER` {
   580  			q = instanceWMIQuery(w.Name, q)
   581  			label = strings.ToLower(w.Name[6:len(w.Name)])
   582  		}
   583  		if err := queryWmi(q, &dst); err != nil {
   584  			return nil, slog.Wrap(err)
   585  		}
   586  		for _, v := range dst {
   587  			tags := opentsdb.TagSet{"instance": label}
   588  			Add(&md, "mssql.buffer.page_life_expectancy", v.PageLifeExpectancy, tags, metadata.Gauge, metadata.Second, descMSSQLPageLifeExpectancy)
   589  			if v.BufferCacheHitRatio_Base != 0 {
   590  				Add(&md, "mssql.buffer.cache_hit_ratio", float64(v.BufferCacheHitRatio*100)/float64(v.BufferCacheHitRatio_Base), tags, metadata.Gauge, metadata.Pct, descBufferCacheHitRatio)
   591  			}
   592  		}
   593  	}
   594  	return md, nil
   595  }
   596  
   597  const (
   598  	descMSSQLPageLifeExpectancy = "Indicates the number of seconds a page will stay in the buffer pool without references."
   599  	descBufferCacheHitRatio     = "Percentage of pages that were found in the buffer pool without having to incur a read from disk."
   600  )
   601  
   602  type Win32_PerfRawData_MSSQLSERVER_SQLServerBufferManager struct {
   603  	PageLifeExpectancy       uint64
   604  	BufferCacheHitRatio      uint64
   605  	BufferCacheHitRatio_Base uint64
   606  }
   607  
   608  func instanceWMIQuery(instancename string, wmiquery string) string {
   609  	var newname = strings.Replace(strings.Replace(instancename, `$`, "", 1), `_`, "", -1)
   610  	return strings.Replace(wmiquery, `MSSQLSERVER_SQLServer`, newname+`_`+newname, 1)
   611  }