From cf3a7d113847595b6a4d15f33db891a8b0cbf371 Mon Sep 17 00:00:00 2001 From: Rune Darrud Date: Tue, 26 Jan 2016 00:32:57 +0100 Subject: [PATCH] Added testcase, updated readme. --- plugins/inputs/win_perfcounters/README.md | 89 +++++++++-------- .../win_perfcounters/win_perfcounters.go | 36 +++++-- .../win_perfcounters_notwindows.go | 2 + .../win_perfcounters/win_perfcounters_test.go | 97 +++++++++++++++++++ 4 files changed, 179 insertions(+), 45 deletions(-) create mode 100644 plugins/inputs/win_perfcounters/win_perfcounters_test.go diff --git a/plugins/inputs/win_perfcounters/README.md b/plugins/inputs/win_perfcounters/README.md index 674a7ad5a92b8..c20cdd8e826a9 100644 --- a/plugins/inputs/win_perfcounters/README.md +++ b/plugins/inputs/win_perfcounters/README.md @@ -7,18 +7,20 @@ The way this plugin works is that on load of Telegraf, the plugin will be handed The examples contained in this file have been found on the internet as counters used when performance monitoring Active Directory and IIS in perticular. There are a lot other good objects to monitor, if you know what to look for. This file is likely to be updated in the future with more examples for useful configurations for separate scenarios. ### Entry -One entry consists of the TOML header to start with, `[[inputs.win_perfcounters.object]]`. This must follow before other plugins code, beneath the main win_perfcounters entry, `[[inputs.win_perfcounters]]`. +A new configuration entry consists of the TOML header to start with, `[[inputs.win_perfcounters.object]]`. This must follow before other plugins configuration, beneath the main win_perfcounters entry, `[[inputs.win_perfcounters]]`. -Following this is 3 required key/value pairs and the three optional parameters. +Following this is 3 required key/value pairs and the three optional parameters and their usage. ### ObjectName **Required** + ObjectName is the Object to query for, like Processor, DirectoryServices, LogicalDisk or similar. Example: `ObjectName = "LogicalDisk"` ### Instances **Required** + Instances (this is an array) is the instances of a counter you would like returned, it can be one or more values. Example, `Instances = ["C:","D:","E:"]` will return only for the instances C:, D: and E: where relevant. To get all instnaces of a Counter, use ["*"] only. By default any results containing _Total are stripped, unless this is specified as the wanted instance. Alternatively see the option IncludeTotal below. @@ -26,7 +28,8 @@ Example, `Instances = ["C:","D:","E:"]` will return only for the instances C:, D Some Objects does not have instances to select from at all, here only one option is valid if you want data back, and that is to specify `Instances = ["------"]`. ### Counters -**Require** +**Required** + Counters (this is an array) is the counters of the ObjectName you would like returned, it can also be one or more values. Example: `Counters = ["% Idle Time", "% Disk Read Time", "% Disk Write Time"]` @@ -34,20 +37,28 @@ This must be specified for every counter you want the results of, it is not poss ### Measurement *Optional* + This key is optional, if it is not set it will be win_perfcounters. In InfluxDB this is the key by which the returned data is stored underneath, so for ordering your data in a good manner, this is a good key to set with where you want your IIS and Disk results stored, separate from Processor results. Example: `Measurement = "win_disk" ### IncludeTotal *Optional* + This key is optional, it is a simple bool. If it is not set to true or included it is treated as false. This key only has an effect if Instances is set to "*" and you would also like all instances containg _Total returned, like "_Total", "0,_Total" and so on where applicable (Processor Information is one example). ### WarnOnMissing *Optional* + This key is optional, it is a simple bool. If it is not set to true or included it is treated as false. This only has an effect on the first execution of the plugin, it will print out any ObjectName/Instance/Counter combinations asked for that does not match. Useful when debugging new configurations. +### FailOnMissing +*Internal* + +This key should not be used, it is for testing purposes only. It is a simple bool, if it is not set to true or included this is treaded as false. If this is set to true, the plugin will abort and end prematurely if any of the combinations of ObjectName/Instances/Counters are invalid. + ## Examples ### Generic Queries @@ -121,7 +132,7 @@ This only has an effect on the first execution of the plugin, it will print out #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). #WarnOnMissing = false # Print out when the performance counter is missing, either of object, counter or instance. ``` -### DFS Rerplication + Domain Controllers +### DFS Replication + Domain Controllers ``` [[inputs.win_perfcounters.object]] # AD, DFS R, Useful if the server hosts a DFS Replication folder or is a Domain Controller @@ -151,6 +162,40 @@ This only has an effect on the first execution of the plugin, it will print out Measurement = "win_http_queues" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). + [[inputs.win_perfcounters.object]] + # IIS, ASP.NET Applications + ObjectName = "ASP.NET Applications" + Counters = ["Cache Total Entries","Cache Total Hit Ratio","Cache Total Turnover Rate","Output Cache Entries","Output Cache Hits","Output Cache Hit Ratio","Output Cache Turnover Rate","Compilations Total","Errors Total/Sec","Pipeline Instance Count","Requests Executing","Requests in Application Queue","Requests/Sec"] + Instances = ["*"] + Measurement = "win_aspnet_app" + #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). + + [[inputs.win_perfcounters.object]] + # IIS, ASP.NET + ObjectName = "ASP.NET" + Counters = ["Application Restarts","Request Wait Time","Requests Current","Requests Queued","Requests Rejected"] + Instances = ["*"] + Measurement = "win_aspnet" + #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). + + [[inputs.win_perfcounters.object]] + # IIS, Web Service + ObjectName = "Web Service" + Counters = ["Get Requests/sec","Post Requests/sec","Connection Attempts/sec","Current Connections","ISAPI Extension Requests/sec"] + Instances = ["*"] + Measurement = "win_websvc" + #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). + + [[inputs.win_perfcounters.object]] + # Web Service Cache / IIS + ObjectName = "Web Service Cache" + Counters = ["URI Cache Hits %","Kernel: URI Cache Hits %","File Cache Hits %"] + Instances = ["*"] + Measurement = "win_websvc_cache" + #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). +``` +### Process +``` [[inputs.win_perfcounters.object]] # Process metrics, in this case for IIS only ObjectName = "Process" @@ -158,7 +203,8 @@ This only has an effect on the first execution of the plugin, it will print out Instances = ["w3wp"] Measurement = "win_proc" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - +``` +### .NET Montioring [[inputs.win_perfcounters.object]] # .NET CLR Exceptions, in this case for IIS only ObjectName = ".NET CLR Exceptions" @@ -206,37 +252,4 @@ This only has an effect on the first execution of the plugin, it will print out Instances = ["w3wp"] Measurement = "win_dotnet_security" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - - [[inputs.win_perfcounters.object]] - # IIS, ASP.NET Applications - ObjectName = "ASP.NET Applications" - Counters = ["Cache Total Entries","Cache Total Hit Ratio","Cache Total Turnover Rate","Output Cache Entries","Output Cache Hits","Output Cache Hit Ratio","Output Cache Turnover Rate","Compilations Total","Errors Total/Sec","Pipeline Instance Count","Requests Executing","Requests in Application Queue","Requests/Sec"] - Instances = ["*"] - Measurement = "win_aspnet_app" - #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - - [[inputs.win_perfcounters.object]] - # IIS, ASP.NET - ObjectName = "ASP.NET" - Counters = ["Application Restarts","Request Wait Time","Requests Current","Requests Queued","Requests Rejected"] - Instances = ["*"] - Measurement = "win_aspnet" - #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - - [[inputs.win_perfcounters.object]] - # IIS, Web Service - ObjectName = "Web Service" - Counters = ["Get Requests/sec","Post Requests/sec","Connection Attempts/sec","Current Connections","ISAPI Extension Requests/sec"] - Instances = ["*"] - Measurement = "win_websvc" - #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - - [[inputs.win_perfcounters.object]] - # Web Service Cache / IIS - ObjectName = "Web Service Cache" - Counters = ["URI Cache Hits %","Kernel: URI Cache Hits %","File Cache Hits %"] - Instances = ["*"] - Measurement = "win_websvc_cache" - #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). - ``` diff --git a/plugins/inputs/win_perfcounters/win_perfcounters.go b/plugins/inputs/win_perfcounters/win_perfcounters.go index 4beafd91938f3..2d723ac228a8f 100644 --- a/plugins/inputs/win_perfcounters/win_perfcounters.go +++ b/plugins/inputs/win_perfcounters/win_perfcounters.go @@ -1,8 +1,9 @@ -// +build windows - package win_perfcounters +// +build windows + import ( + "errors" "fmt" "strings" "syscall" @@ -63,6 +64,7 @@ type perfobject struct { Instances []string Measurement string WarnOnMissing bool + FailOnMissing bool IncludeTotal bool } @@ -105,7 +107,7 @@ func (m *Win_PerfCounters) SampleConfig() string { return sampleConfig } -func (m *Win_PerfCounters) ParseConfig(metrics *itemList) { +func (m *Win_PerfCounters) ParseConfig(metrics *itemList) error { var query string for _, PerfObject := range m.Object { @@ -127,24 +129,40 @@ func (m *Win_PerfCounters) ParseConfig(metrics *itemList) { } AddItem(query, objectname, counter, instance, PerfObject.Measurement, PerfObject.IncludeTotal) } else if exists == 3221228472 { // win.PDH_CSTATUS_NO_OBJECT - if PerfObject.WarnOnMissing { + if PerfObject.WarnOnMissing || PerfObject.FailOnMissing { fmt.Printf("Performance Object '%s' does not exist in query: %s\n", objectname, query) + if PerfObject.FailOnMissing { + err := errors.New("Performance object does not exist") + } } } else if exists == 3221228473 { //win.PDH_CSTATUS_NO_COUNTER - if PerfObject.WarnOnMissing { + if PerfObject.WarnOnMissing || PerfObject.FailOnMissing { fmt.Printf("Counter '%s' does not exist in query: %s\n", counter, query) + if PerfObject.FailOnMissing { + err := errors.New("Counter in Performance object does not exist") + } } } else if exists == 2147485649 { //win.PDH_CSTATUS_NO_INSTANCE - if PerfObject.WarnOnMissing { + if PerfObject.WarnOnMissing || PerfObject.FailOnMissing { fmt.Printf("Instance '%s' does not exist in query: %s\n", instance, query) + if PerfObject.FailOnMissing { + err := errors.New("Instance in Performance object does not exist") + } } } else { fmt.Printf("Invalid result: %v, query: %s\n", exists, query) + if PerfObject.FailOnMissing { + err := errors.New("Invalid query for Performance Counters") + } + } + if err != nil { + return err } } } } configParsed = true + return nil } func (m *Win_PerfCounters) Cleanup(metrics *itemList) { @@ -161,7 +179,11 @@ func (m *Win_PerfCounters) Gather(acc inputs.Accumulator) error { // We only need to parse the config during the init, it uses the global variable after. if configParsed == false { - m.ParseConfig(&metrics) + err := m.ParseConfig(&metrics) + if err != nil { + fmt.Println("Error occured during parsing the configuration") + return err + } } // When interrupt or terminate is called. diff --git a/plugins/inputs/win_perfcounters/win_perfcounters_notwindows.go b/plugins/inputs/win_perfcounters/win_perfcounters_notwindows.go index f4646266499be..948e486af6687 100644 --- a/plugins/inputs/win_perfcounters/win_perfcounters_notwindows.go +++ b/plugins/inputs/win_perfcounters/win_perfcounters_notwindows.go @@ -1 +1,3 @@ +package win_perfcounters + // +build !windows diff --git a/plugins/inputs/win_perfcounters/win_perfcounters_test.go b/plugins/inputs/win_perfcounters/win_perfcounters_test.go new file mode 100644 index 0000000000000..21955dbadfa3f --- /dev/null +++ b/plugins/inputs/win_perfcounters/win_perfcounters_test.go @@ -0,0 +1,97 @@ +package win_perfcounters + +import ( + "testing" + + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" +) + +func TestWinPerfcountersGet(t *testing.T) { + var instances []string + var counters []string + + objectname := "Processor Information" + instances[0] = "_Total" + counters[0] = "% Processor Time" + + var measurement string = "none" + var warnonmissing bool = false + var failonmissing bool = true + var includetotal bool = false + + p := perfobject{ObjectName: objectname, Instances: instances, Measurement: "none", WarnOnMissing: warnonmissing, FailOnMissing: failonmissing, IncludeTotal: includetotal} + + m := Win_PerfCounters{PrintValid: true, Object: &s} + + var acc testutil.Accumulator + err := m.Gather(&acc) + require.NoError(t, err) +} + +func TestWinPerfcountersError1(t *testing.T) { + + var instances []string + var counters []string + + objectname := "Processor InformationERROR" + instances[0] = "_Total" + counters[0] = "% Processor Time" + + var measurement string = "none" + var warnonmissing bool = false + var failonmissing bool = true + var includetotal bool = false + + p := perfobject{ObjectName: objectname, Instances: instances, Measurement: "none", WarnOnMissing: warnonmissing, FailOnMissing: failonmissing, IncludeTotal: includetotal} + + m := Win_PerfCounters{PrintValid: true, Object: &s} + + var acc testutil.Accumulator + err := m.Gather(&acc) + require.Error(t, err) +} + +func TestWinPerfcountersError2(t *testing.T) { + var instances []string + var counters []string + + objectname := "Processor Information" + instances[0] = "_TotalERROR" + counters[0] = "% Processor Time" + + var measurement string = "none" + var warnonmissing bool = false + var failonmissing bool = true + var includetotal bool = false + + p := perfobject{ObjectName: objectname, Instances: instances, Measurement: "none", WarnOnMissing: warnonmissing, FailOnMissing: failonmissing, IncludeTotal: includetotal} + + m := Win_PerfCounters{PrintValid: true, Object: &s} + + var acc testutil.Accumulator + err := m.Gather(&acc) + require.Error(t, err) +} + +func TestWinPerfcountersError3(t *testing.T) { + var instances []string + var counters []string + + objectname := "Processor Information" + instances[0] = "_Total" + counters[0] = "% Processor TimeERROR" + + var measurement string = "none" + var warnonmissing bool = false + var failonmissing bool = true + var includetotal bool = false + + p := perfobject{ObjectName: objectname, Instances: instances, Measurement: "none", WarnOnMissing: warnonmissing, FailOnMissing: failonmissing, IncludeTotal: includetotal} + + m := Win_PerfCounters{PrintValid: true, Object: &s} + + var acc testutil.Accumulator + err := m.Gather(&acc) + require.Error(t, err) +}