Updating system plugins for 0.3.0
This commit is contained in:
		
							parent
							
								
									ee8d99b955
								
							
						
					
					
						commit
						50fc3ec974
					
				
							
								
								
									
										13
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										13
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -1,3 +1,16 @@ | ||||||
|  | ## v0.3.0 [unreleased] | ||||||
|  | 
 | ||||||
|  | ### Release Notes | ||||||
|  | - **breaking change** the `io` plugin has been renamed `diskio` | ||||||
|  | - **breaking change** Plugin measurements aggregated into a single measurement. | ||||||
|  | 
 | ||||||
|  | ### Features | ||||||
|  | - Plugin measurements aggregated into a single measurement. | ||||||
|  | - Added ability to specify per-plugin tags | ||||||
|  | - Added ability to specify per-plugin measurement suffix and prefix | ||||||
|  | 
 | ||||||
|  | ### Bugfixes | ||||||
|  | 
 | ||||||
| ## v0.2.5 [unreleased] | ## v0.2.5 [unreleased] | ||||||
| 
 | 
 | ||||||
| ### Features | ### Features | ||||||
|  |  | ||||||
|  | @ -0,0 +1,177 @@ | ||||||
|  | # Telegraf Configuration | ||||||
|  | 
 | ||||||
|  | ## Plugin Configuration | ||||||
|  | 
 | ||||||
|  | There are some configuration options that are configurable per plugin: | ||||||
|  | 
 | ||||||
|  | * **name_override**: Override the base name of the measurement. | ||||||
|  | (Default is the name of the plugin). | ||||||
|  | * **name_prefix**: Specifies a prefix to attach to the measurement name. | ||||||
|  | * **name_suffix**: Specifies a suffix to attach to the measurement name. | ||||||
|  | * **tags**: A map of tags to apply to a specific plugin's measurements. | ||||||
|  | 
 | ||||||
|  | ### Plugin Filters | ||||||
|  | 
 | ||||||
|  | There are also filters that can be configured per plugin: | ||||||
|  | 
 | ||||||
|  | * **pass**: An array of strings that is used to filter metrics generated by the | ||||||
|  | current plugin. Each string in the array is tested as a glob match against field names | ||||||
|  | and if it matches, the field is emitted. | ||||||
|  | * **drop**: The inverse of pass, if a field name matches, it is not emitted. | ||||||
|  | * **tagpass**: tag names and arrays of strings that are used to filter | ||||||
|  | measurements by the current plugin. Each string in the array is tested as a glob | ||||||
|  | match against the tag name, and if it matches the measurement is emitted. | ||||||
|  | * **tagdrop**: The inverse of tagpass. If a tag matches, the measurement is not emitted. | ||||||
|  | This is tested on measurements that have passed the tagpass test. | ||||||
|  | * **interval**: How often to gather this metric. Normal plugins use a single | ||||||
|  | global interval, but if one particular plugin should be run less or more often, | ||||||
|  | you can configure that here. | ||||||
|  | 
 | ||||||
|  | ### Plugin Configuration Examples | ||||||
|  | 
 | ||||||
|  | This is a full working config that will output CPU data to an InfluxDB instance | ||||||
|  | at 192.168.59.103:8086, tagging measurements with dc="denver-1". It will output | ||||||
|  | measurements at a 10s interval and will collect per-cpu data, dropping any | ||||||
|  | fields which begin with `time_`. | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [tags] | ||||||
|  |   dc = "denver-1" | ||||||
|  | 
 | ||||||
|  | [agent] | ||||||
|  |   interval = "10s" | ||||||
|  | 
 | ||||||
|  | # OUTPUTS | ||||||
|  | [outputs] | ||||||
|  | [[outputs.influxdb]] | ||||||
|  |   url = "http://192.168.59.103:8086" # required. | ||||||
|  |   database = "telegraf" # required. | ||||||
|  |   precision = "s" | ||||||
|  | 
 | ||||||
|  | # PLUGINS | ||||||
|  | [plugins] | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = true | ||||||
|  |   totalcpu = false | ||||||
|  |   # filter all fields beginning with 'time_' | ||||||
|  |   drop = ["time_*"] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Plugin Config: tagpass and tagdrop | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [plugins] | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = true | ||||||
|  |   totalcpu = false | ||||||
|  |   drop = ["cpu_time"] | ||||||
|  |   # Don't collect CPU data for cpu6 & cpu7 | ||||||
|  |   [plugins.cpu.tagdrop] | ||||||
|  |     cpu = [ "cpu6", "cpu7" ] | ||||||
|  | 
 | ||||||
|  | [[plugins.disk]] | ||||||
|  |   [plugins.disk.tagpass] | ||||||
|  |     # tagpass conditions are OR, not AND. | ||||||
|  |     # If the (filesystem is ext4 or xfs) OR (the path is /opt or /home) | ||||||
|  |     # then the metric passes | ||||||
|  |     fstype = [ "ext4", "xfs" ] | ||||||
|  |     # Globs can also be used on the tag values | ||||||
|  |     path = [ "/opt", "/home*" ] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Plugin Config: pass and drop | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | # Drop all metrics for guest & steal CPU usage | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = false | ||||||
|  |   totalcpu = true | ||||||
|  |   drop = ["usage_guest", "usage_steal"] | ||||||
|  | 
 | ||||||
|  | # Only store inode related metrics for disks | ||||||
|  | [[plugins.disk]] | ||||||
|  |   pass = ["inodes*"] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Plugin config: prefix, suffix, and override | ||||||
|  | 
 | ||||||
|  | This plugin will emit measurements with the name `cpu_total` | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   name_suffix = "_total" | ||||||
|  |   percpu = false | ||||||
|  |   totalcpu = true | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This will emit measurements with the name `foobar` | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   name_override = "foobar" | ||||||
|  |   percpu = false | ||||||
|  |   totalcpu = true | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Plugin config: tags | ||||||
|  | 
 | ||||||
|  | This plugin will emit measurements with two additional tags: `tag1=foo` and | ||||||
|  | `tag2=bar` | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = false | ||||||
|  |   totalcpu = true | ||||||
|  |   [plugins.cpu.tags] | ||||||
|  |     tag1 = "foo" | ||||||
|  |     tag2 = "bar" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Multiple plugins of the same type | ||||||
|  | 
 | ||||||
|  | Additional plugins (or outputs) of the same type can be specified, | ||||||
|  | just define more instances in the config file: | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = false | ||||||
|  |   totalcpu = true | ||||||
|  | 
 | ||||||
|  | [[plugins.cpu]] | ||||||
|  |   percpu = true | ||||||
|  |   totalcpu = false | ||||||
|  |   drop = ["cpu_time*"] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Output Configuration | ||||||
|  | 
 | ||||||
|  | Telegraf also supports specifying multiple output sinks to send data to, | ||||||
|  | configuring each output sink is different, but examples can be | ||||||
|  | found by running `telegraf -sample-config`. | ||||||
|  | 
 | ||||||
|  | Outputs also support the same configurable options as plugins | ||||||
|  | (pass, drop, tagpass, tagdrop), added in 0.2.4 | ||||||
|  | 
 | ||||||
|  | ```toml | ||||||
|  | [[outputs.influxdb]] | ||||||
|  |   urls = [ "http://localhost:8086" ] | ||||||
|  |   database = "telegraf" | ||||||
|  |   precision = "s" | ||||||
|  |   # Drop all measurements that start with "aerospike" | ||||||
|  |   drop = ["aerospike*"] | ||||||
|  | 
 | ||||||
|  | [[outputs.influxdb]] | ||||||
|  |   urls = [ "http://localhost:8086" ] | ||||||
|  |   database = "telegraf-aerospike-data" | ||||||
|  |   precision = "s" | ||||||
|  |   # Only accept aerospike data: | ||||||
|  |   pass = ["aerospike*"] | ||||||
|  | 
 | ||||||
|  | [[outputs.influxdb]] | ||||||
|  |   urls = [ "http://localhost:8086" ] | ||||||
|  |   database = "telegraf-cpu0-data" | ||||||
|  |   precision = "s" | ||||||
|  |   # Only store measurements where the tag "cpu" matches the value "cpu0" | ||||||
|  |   [outputs.influxdb.tagpass] | ||||||
|  |     cpu = ["cpu0"] | ||||||
|  | ``` | ||||||
							
								
								
									
										133
									
								
								README.md
								
								
								
								
							
							
						
						
									
										133
									
								
								README.md
								
								
								
								
							|  | @ -116,99 +116,10 @@ unit parser, e.g. "10s" for 10 seconds or "5m" for 5 minutes. | ||||||
| * **debug**: Set to true to gather and send metrics to STDOUT as well as | * **debug**: Set to true to gather and send metrics to STDOUT as well as | ||||||
| InfluxDB. | InfluxDB. | ||||||
| 
 | 
 | ||||||
| ## Plugin Options | ## Configuration | ||||||
| 
 | 
 | ||||||
| There are 5 configuration options that are configurable per plugin: | See the [configuration guide](CONFIGURATION.md) for a rundown of the more advanced | ||||||
| 
 | configuration options. | ||||||
| * **pass**: An array of strings that is used to filter metrics generated by the |  | ||||||
| current plugin. Each string in the array is tested as a glob match against metric names |  | ||||||
| and if it matches, the metric is emitted. |  | ||||||
| * **drop**: The inverse of pass, if a metric name matches, it is not emitted. |  | ||||||
| * **tagpass**: tag names and arrays of strings that are used to filter metrics by the current plugin. Each string in the array is tested as a glob match against |  | ||||||
| the tag name, and if it matches the metric is emitted. |  | ||||||
| * **tagdrop**: The inverse of tagpass. If a tag matches, the metric is not emitted. |  | ||||||
| This is tested on metrics that have passed the tagpass test. |  | ||||||
| * **interval**: How often to gather this metric. Normal plugins use a single |  | ||||||
| global interval, but if one particular plugin should be run less or more often, |  | ||||||
| you can configure that here. |  | ||||||
| 
 |  | ||||||
| ### Plugin Configuration Examples |  | ||||||
| 
 |  | ||||||
| This is a full working config that will output CPU data to an InfluxDB instance |  | ||||||
| at 192.168.59.103:8086, tagging measurements with dc="denver-1". It will output |  | ||||||
| measurements at a 10s interval and will collect per-cpu data, dropping any |  | ||||||
| measurements which begin with `cpu_time`. |  | ||||||
| 
 |  | ||||||
| ```toml |  | ||||||
| [tags] |  | ||||||
|   dc = "denver-1" |  | ||||||
| 
 |  | ||||||
| [agent] |  | ||||||
|   interval = "10s" |  | ||||||
| 
 |  | ||||||
| # OUTPUTS |  | ||||||
| [outputs] |  | ||||||
| [[outputs.influxdb]] |  | ||||||
|   url = "http://192.168.59.103:8086" # required. |  | ||||||
|   database = "telegraf" # required. |  | ||||||
|   precision = "s" |  | ||||||
| 
 |  | ||||||
| # PLUGINS |  | ||||||
| [plugins] |  | ||||||
| [[plugins.cpu]] |  | ||||||
|   percpu = true |  | ||||||
|   totalcpu = false |  | ||||||
|   drop = ["cpu_time*"] |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Below is how to configure `tagpass` and `tagdrop` parameters |  | ||||||
| 
 |  | ||||||
| ```toml |  | ||||||
| [plugins] |  | ||||||
| [[plugins.cpu]] |  | ||||||
|   percpu = true |  | ||||||
|   totalcpu = false |  | ||||||
|   drop = ["cpu_time"] |  | ||||||
|   # Don't collect CPU data for cpu6 & cpu7 |  | ||||||
|   [plugins.cpu.tagdrop] |  | ||||||
|     cpu = [ "cpu6", "cpu7" ] |  | ||||||
| 
 |  | ||||||
| [[plugins.disk]] |  | ||||||
|   [plugins.disk.tagpass] |  | ||||||
|     # tagpass conditions are OR, not AND. |  | ||||||
|     # If the (filesystem is ext4 or xfs) OR (the path is /opt or /home) |  | ||||||
|     # then the metric passes |  | ||||||
|     fstype = [ "ext4", "xfs" ] |  | ||||||
|     # Globs can also be used on the tag values |  | ||||||
|     path = [ "/opt", "/home*" ] |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Below is how to configure `pass` and `drop` parameters |  | ||||||
| 
 |  | ||||||
| ```toml |  | ||||||
| # Drop all metrics for guest CPU usage |  | ||||||
| [[plugins.cpu]] |  | ||||||
|   drop = [ "cpu_usage_guest" ] |  | ||||||
| 
 |  | ||||||
| # Only store inode related metrics for disks |  | ||||||
| [[plugins.disk]] |  | ||||||
|   pass = [ "disk_inodes*" ] |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Additional plugins (or outputs) of the same type can be specified, |  | ||||||
| just define more instances in the config file: |  | ||||||
| 
 |  | ||||||
| ```toml |  | ||||||
| [[plugins.cpu]] |  | ||||||
|   percpu = false |  | ||||||
|   totalcpu = true |  | ||||||
| 
 |  | ||||||
| [[plugins.cpu]] |  | ||||||
|   percpu = true |  | ||||||
|   totalcpu = false |  | ||||||
|   drop = ["cpu_time*"] |  | ||||||
| ``` |  | ||||||
| 
 | 
 | ||||||
| ## Supported Plugins | ## Supported Plugins | ||||||
| 
 | 
 | ||||||
|  | @ -226,7 +137,7 @@ Telegraf currently has support for collecting metrics from: | ||||||
| * haproxy | * haproxy | ||||||
| * httpjson (generic JSON-emitting http service plugin) | * httpjson (generic JSON-emitting http service plugin) | ||||||
| * influxdb | * influxdb | ||||||
| * jolokia (remote JMX with JSON over HTTP) | * jolokia | ||||||
| * leofs | * leofs | ||||||
| * lustre2 | * lustre2 | ||||||
| * mailchimp | * mailchimp | ||||||
|  | @ -249,10 +160,10 @@ Telegraf currently has support for collecting metrics from: | ||||||
| * system | * system | ||||||
|     * cpu |     * cpu | ||||||
|     * mem |     * mem | ||||||
|     * io |  | ||||||
|     * net |     * net | ||||||
|     * netstat |     * netstat | ||||||
|     * disk |     * disk | ||||||
|  |     * diskio | ||||||
|     * swap |     * swap | ||||||
| 
 | 
 | ||||||
| ## Supported Service Plugins | ## Supported Service Plugins | ||||||
|  | @ -265,40 +176,6 @@ Telegraf can collect metrics via the following services: | ||||||
| We'll be adding support for many more over the coming months. Read on if you | We'll be adding support for many more over the coming months. Read on if you | ||||||
| want to add support for another service or third-party API. | want to add support for another service or third-party API. | ||||||
| 
 | 
 | ||||||
| ## Output options |  | ||||||
| 
 |  | ||||||
| Telegraf also supports specifying multiple output sinks to send data to, |  | ||||||
| configuring each output sink is different, but examples can be |  | ||||||
| found by running `telegraf -sample-config`. |  | ||||||
| 
 |  | ||||||
| Outputs also support the same configurable options as plugins |  | ||||||
| (pass, drop, tagpass, tagdrop), added in 0.2.4 |  | ||||||
| 
 |  | ||||||
| ```toml |  | ||||||
| [[outputs.influxdb]] |  | ||||||
|   urls = [ "http://localhost:8086" ] |  | ||||||
|   database = "telegraf" |  | ||||||
|   precision = "s" |  | ||||||
|   # Drop all measurements that start with "aerospike" |  | ||||||
|   drop = ["aerospike*"] |  | ||||||
| 
 |  | ||||||
| [[outputs.influxdb]] |  | ||||||
|   urls = [ "http://localhost:8086" ] |  | ||||||
|   database = "telegraf-aerospike-data" |  | ||||||
|   precision = "s" |  | ||||||
|   # Only accept aerospike data: |  | ||||||
|   pass = ["aerospike*"] |  | ||||||
| 
 |  | ||||||
| [[outputs.influxdb]] |  | ||||||
|   urls = [ "http://localhost:8086" ] |  | ||||||
|   database = "telegraf-cpu0-data" |  | ||||||
|   precision = "s" |  | ||||||
|   # Only store measurements where the tag "cpu" matches the value "cpu0" |  | ||||||
|   [outputs.influxdb.tagpass] |  | ||||||
|     cpu = ["cpu0"] |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ## Supported Outputs | ## Supported Outputs | ||||||
| 
 | 
 | ||||||
| * influxdb | * influxdb | ||||||
|  |  | ||||||
|  | @ -69,31 +69,73 @@ func (ac *accumulator) AddFields( | ||||||
| 	tags map[string]string, | 	tags map[string]string, | ||||||
| 	t ...time.Time, | 	t ...time.Time, | ||||||
| ) { | ) { | ||||||
| 	// Validate uint64 and float64 fields
 | 	if !ac.pluginConfig.Filter.ShouldTagsPass(tags) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Override measurement name if set
 | ||||||
|  | 	if len(ac.pluginConfig.NameOverride) != 0 { | ||||||
|  | 		measurement = ac.pluginConfig.NameOverride | ||||||
|  | 	} | ||||||
|  | 	// Apply measurement prefix and suffix if set
 | ||||||
|  | 	if len(ac.pluginConfig.MeasurementPrefix) != 0 { | ||||||
|  | 		measurement = ac.pluginConfig.MeasurementPrefix + measurement | ||||||
|  | 	} | ||||||
|  | 	if len(ac.pluginConfig.MeasurementSuffix) != 0 { | ||||||
|  | 		measurement = measurement + ac.pluginConfig.MeasurementSuffix | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if tags == nil { | ||||||
|  | 		tags = make(map[string]string) | ||||||
|  | 	} | ||||||
|  | 	// Apply plugin-wide tags if set
 | ||||||
|  | 	for k, v := range ac.pluginConfig.Tags { | ||||||
|  | 		if _, ok := tags[k]; !ok { | ||||||
|  | 			tags[k] = v | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Apply daemon-wide tags if set
 | ||||||
|  | 	for k, v := range ac.defaultTags { | ||||||
|  | 		if _, ok := tags[k]; !ok { | ||||||
|  | 			tags[k] = v | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	result := make(map[string]interface{}) | ||||||
| 	for k, v := range fields { | 	for k, v := range fields { | ||||||
|  | 		// Filter out any filtered fields
 | ||||||
|  | 		if ac.pluginConfig != nil { | ||||||
|  | 			if !ac.pluginConfig.Filter.ShouldPass(k) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		result[k] = v | ||||||
|  | 
 | ||||||
|  | 		// Validate uint64 and float64 fields
 | ||||||
| 		switch val := v.(type) { | 		switch val := v.(type) { | ||||||
| 		case uint64: | 		case uint64: | ||||||
| 			// InfluxDB does not support writing uint64
 | 			// InfluxDB does not support writing uint64
 | ||||||
| 			if val < uint64(9223372036854775808) { | 			if val < uint64(9223372036854775808) { | ||||||
| 				fields[k] = int64(val) | 				result[k] = int64(val) | ||||||
| 			} else { | 			} else { | ||||||
| 				fields[k] = int64(9223372036854775807) | 				result[k] = int64(9223372036854775807) | ||||||
| 			} | 			} | ||||||
| 		case float64: | 		case float64: | ||||||
| 			// NaNs are invalid values in influxdb, skip measurement
 | 			// NaNs are invalid values in influxdb, skip measurement
 | ||||||
| 			if math.IsNaN(val) || math.IsInf(val, 0) { | 			if math.IsNaN(val) || math.IsInf(val, 0) { | ||||||
| 				if ac.debug { | 				if ac.debug { | ||||||
| 					log.Printf("Measurement [%s] has a NaN or Inf field, skipping", | 					log.Printf("Measurement [%s] field [%s] has a NaN or Inf "+ | ||||||
| 						measurement) | 						"field, skipping", | ||||||
|  | 						measurement, k) | ||||||
| 				} | 				} | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	fields = nil | ||||||
|  | 	if len(result) == 0 { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if tags == nil { |  | ||||||
| 		tags = make(map[string]string) |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	var timestamp time.Time | 	var timestamp time.Time | ||||||
| 	if len(t) > 0 { | 	if len(t) > 0 { | ||||||
|  | @ -106,19 +148,7 @@ func (ac *accumulator) AddFields( | ||||||
| 		measurement = ac.prefix + measurement | 		measurement = ac.prefix + measurement | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ac.pluginConfig != nil { | 	pt, err := client.NewPoint(measurement, tags, result, timestamp) | ||||||
| 		if !ac.pluginConfig.Filter.ShouldPass(measurement) || !ac.pluginConfig.Filter.ShouldTagsPass(tags) { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for k, v := range ac.defaultTags { |  | ||||||
| 		if _, ok := tags[k]; !ok { |  | ||||||
| 			tags[k] = v |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	pt, err := client.NewPoint(measurement, tags, fields, timestamp) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Printf("Error adding point [%s]: %s\n", measurement, err.Error()) | 		log.Printf("Error adding point [%s]: %s\n", measurement, err.Error()) | ||||||
| 		return | 		return | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								agent.go
								
								
								
								
							
							
						
						
									
										6
									
								
								agent.go
								
								
								
								
							|  | @ -104,7 +104,7 @@ func (a *Agent) gatherParallel(pointChan chan *client.Point) error { | ||||||
| 
 | 
 | ||||||
| 			acc := NewAccumulator(plugin.Config, pointChan) | 			acc := NewAccumulator(plugin.Config, pointChan) | ||||||
| 			acc.SetDebug(a.Config.Agent.Debug) | 			acc.SetDebug(a.Config.Agent.Debug) | ||||||
| 			acc.SetPrefix(plugin.Name + "_") | 			// acc.SetPrefix(plugin.Name + "_")
 | ||||||
| 			acc.SetDefaultTags(a.Config.Tags) | 			acc.SetDefaultTags(a.Config.Tags) | ||||||
| 
 | 
 | ||||||
| 			if err := plugin.Plugin.Gather(acc); err != nil { | 			if err := plugin.Plugin.Gather(acc); err != nil { | ||||||
|  | @ -141,7 +141,7 @@ func (a *Agent) gatherSeparate( | ||||||
| 
 | 
 | ||||||
| 		acc := NewAccumulator(plugin.Config, pointChan) | 		acc := NewAccumulator(plugin.Config, pointChan) | ||||||
| 		acc.SetDebug(a.Config.Agent.Debug) | 		acc.SetDebug(a.Config.Agent.Debug) | ||||||
| 		acc.SetPrefix(plugin.Name + "_") | 		// acc.SetPrefix(plugin.Name + "_")
 | ||||||
| 		acc.SetDefaultTags(a.Config.Tags) | 		acc.SetDefaultTags(a.Config.Tags) | ||||||
| 
 | 
 | ||||||
| 		if err := plugin.Plugin.Gather(acc); err != nil { | 		if err := plugin.Plugin.Gather(acc); err != nil { | ||||||
|  | @ -187,7 +187,7 @@ func (a *Agent) Test() error { | ||||||
| 	for _, plugin := range a.Config.Plugins { | 	for _, plugin := range a.Config.Plugins { | ||||||
| 		acc := NewAccumulator(plugin.Config, pointChan) | 		acc := NewAccumulator(plugin.Config, pointChan) | ||||||
| 		acc.SetDebug(true) | 		acc.SetDebug(true) | ||||||
| 		acc.SetPrefix(plugin.Name + "_") | 		// acc.SetPrefix(plugin.Name + "_")
 | ||||||
| 
 | 
 | ||||||
| 		fmt.Printf("* Plugin: %s, Collection 1\n", plugin.Name) | 		fmt.Printf("* Plugin: %s, Collection 1\n", plugin.Name) | ||||||
| 		if plugin.Config.Interval != 0 { | 		if plugin.Config.Interval != 0 { | ||||||
|  |  | ||||||
|  | @ -97,7 +97,7 @@ | ||||||
|   # Mountpoints=["/"] |   # Mountpoints=["/"] | ||||||
| 
 | 
 | ||||||
| # Read metrics about disk IO by device | # Read metrics about disk IO by device | ||||||
| [[plugins.io]] | [[plugins.diskio]] | ||||||
|   # By default, telegraf will gather stats for all devices including |   # By default, telegraf will gather stats for all devices including | ||||||
|   # disk partitions. |   # disk partitions. | ||||||
|   # Setting devices will restrict the stats to the specified devices. |   # Setting devices will restrict the stats to the specified devices. | ||||||
|  |  | ||||||
|  | @ -113,6 +113,10 @@ type Filter struct { | ||||||
| // PluginConfig containing a name, interval, and filter
 | // PluginConfig containing a name, interval, and filter
 | ||||||
| type PluginConfig struct { | type PluginConfig struct { | ||||||
| 	Name              string | 	Name              string | ||||||
|  | 	NameOverride      string | ||||||
|  | 	MeasurementPrefix string | ||||||
|  | 	MeasurementSuffix string | ||||||
|  | 	Tags              map[string]string | ||||||
| 	Filter            Filter | 	Filter            Filter | ||||||
| 	Interval          time.Duration | 	Interval          time.Duration | ||||||
| } | } | ||||||
|  | @ -142,12 +146,12 @@ func (ro *RunningOutput) FilterPoints(points []*client.Point) []*client.Point { | ||||||
| 
 | 
 | ||||||
| // ShouldPass returns true if the metric should pass, false if should drop
 | // ShouldPass returns true if the metric should pass, false if should drop
 | ||||||
| // based on the drop/pass filter parameters
 | // based on the drop/pass filter parameters
 | ||||||
| func (f Filter) ShouldPass(measurement string) bool { | func (f Filter) ShouldPass(fieldkey string) bool { | ||||||
| 	if f.Pass != nil { | 	if f.Pass != nil { | ||||||
| 		for _, pat := range f.Pass { | 		for _, pat := range f.Pass { | ||||||
| 			// TODO remove HasPrefix check, leaving it for now for legacy support.
 | 			// TODO remove HasPrefix check, leaving it for now for legacy support.
 | ||||||
| 			// Cam, 2015-12-07
 | 			// Cam, 2015-12-07
 | ||||||
| 			if strings.HasPrefix(measurement, pat) || internal.Glob(pat, measurement) { | 			if strings.HasPrefix(fieldkey, pat) || internal.Glob(pat, fieldkey) { | ||||||
| 				return true | 				return true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -158,7 +162,7 @@ func (f Filter) ShouldPass(measurement string) bool { | ||||||
| 		for _, pat := range f.Drop { | 		for _, pat := range f.Drop { | ||||||
| 			// TODO remove HasPrefix check, leaving it for now for legacy support.
 | 			// TODO remove HasPrefix check, leaving it for now for legacy support.
 | ||||||
| 			// Cam, 2015-12-07
 | 			// Cam, 2015-12-07
 | ||||||
| 			if strings.HasPrefix(measurement, pat) || internal.Glob(pat, measurement) { | 			if strings.HasPrefix(fieldkey, pat) || internal.Glob(pat, fieldkey) { | ||||||
| 				return false | 				return false | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -628,7 +632,8 @@ func buildFilter(tbl *ast.Table) Filter { | ||||||
| 	return f | 	return f | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // buildPlugin parses plugin specific items from the ast.Table, builds the filter and returns a
 | // buildPlugin parses plugin specific items from the ast.Table,
 | ||||||
|  | // builds the filter and returns a
 | ||||||
| // PluginConfig to be inserted into RunningPlugin
 | // PluginConfig to be inserted into RunningPlugin
 | ||||||
| func buildPlugin(name string, tbl *ast.Table) (*PluginConfig, error) { | func buildPlugin(name string, tbl *ast.Table) (*PluginConfig, error) { | ||||||
| 	cp := &PluginConfig{Name: name} | 	cp := &PluginConfig{Name: name} | ||||||
|  | @ -644,10 +649,47 @@ func buildPlugin(name string, tbl *ast.Table) (*PluginConfig, error) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if node, ok := tbl.Fields["name_prefix"]; ok { | ||||||
|  | 		if kv, ok := node.(*ast.KeyValue); ok { | ||||||
|  | 			if str, ok := kv.Value.(*ast.String); ok { | ||||||
|  | 				cp.MeasurementPrefix = str.Value | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if node, ok := tbl.Fields["name_suffix"]; ok { | ||||||
|  | 		if kv, ok := node.(*ast.KeyValue); ok { | ||||||
|  | 			if str, ok := kv.Value.(*ast.String); ok { | ||||||
|  | 				cp.MeasurementSuffix = str.Value | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if node, ok := tbl.Fields["name_override"]; ok { | ||||||
|  | 		if kv, ok := node.(*ast.KeyValue); ok { | ||||||
|  | 			if str, ok := kv.Value.(*ast.String); ok { | ||||||
|  | 				cp.NameOverride = str.Value | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cp.Tags = make(map[string]string) | ||||||
|  | 	if node, ok := tbl.Fields["tags"]; ok { | ||||||
|  | 		if subtbl, ok := node.(*ast.Table); ok { | ||||||
|  | 			if err := toml.UnmarshalTable(subtbl, cp.Tags); err != nil { | ||||||
|  | 				log.Printf("Could not parse tags for plugin %s\n", name) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	delete(tbl.Fields, "name_prefix") | ||||||
|  | 	delete(tbl.Fields, "name_suffix") | ||||||
|  | 	delete(tbl.Fields, "name_override") | ||||||
| 	delete(tbl.Fields, "interval") | 	delete(tbl.Fields, "interval") | ||||||
|  | 	delete(tbl.Fields, "tags") | ||||||
| 	cp.Filter = buildFilter(tbl) | 	cp.Filter = buildFilter(tbl) | ||||||
| 	return cp, nil | 	return cp, nil | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // buildOutput parses output specific items from the ast.Table, builds the filter and returns an
 | // buildOutput parses output specific items from the ast.Table, builds the filter and returns an
 | ||||||
|  | @ -659,5 +701,4 @@ func buildOutput(name string, tbl *ast.Table) (*OutputConfig, error) { | ||||||
| 		Filter: buildFilter(tbl), | 		Filter: buildFilter(tbl), | ||||||
| 	} | 	} | ||||||
| 	return oc, nil | 	return oc, nil | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -105,7 +105,7 @@ urls = ["http://localhost/server-status?auto"] | ||||||
|   drop = ["cpu_time"] |   drop = ["cpu_time"] | ||||||
| 
 | 
 | ||||||
| # Read metrics about disk usage by mount point | # Read metrics about disk usage by mount point | ||||||
| [[plugins.disk]] | [[plugins.diskio]] | ||||||
|   # no configuration |   # no configuration | ||||||
| 
 | 
 | ||||||
| # Read metrics from one or many disque servers | # Read metrics from one or many disque servers | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ package system | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/influxdb/telegraf/plugins" | 	"github.com/influxdb/telegraf/plugins" | ||||||
| 	"github.com/shirou/gopsutil/cpu" | 	"github.com/shirou/gopsutil/cpu" | ||||||
|  | @ -31,7 +32,7 @@ var sampleConfig = ` | ||||||
|   # Whether to report total system cpu stats or not |   # Whether to report total system cpu stats or not | ||||||
|   totalcpu = true |   totalcpu = true | ||||||
|   # Comment this line if you want the raw CPU time metrics |   # Comment this line if you want the raw CPU time metrics | ||||||
|   drop = ["cpu_time*"] |   drop = ["time_*"] | ||||||
| ` | ` | ||||||
| 
 | 
 | ||||||
| func (_ *CPUStats) SampleConfig() string { | func (_ *CPUStats) SampleConfig() string { | ||||||
|  | @ -43,6 +44,7 @@ func (s *CPUStats) Gather(acc plugins.Accumulator) error { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error getting CPU info: %s", err) | 		return fmt.Errorf("error getting CPU info: %s", err) | ||||||
| 	} | 	} | ||||||
|  | 	now := time.Now() | ||||||
| 
 | 
 | ||||||
| 	for i, cts := range times { | 	for i, cts := range times { | ||||||
| 		tags := map[string]string{ | 		tags := map[string]string{ | ||||||
|  | @ -51,21 +53,24 @@ func (s *CPUStats) Gather(acc plugins.Accumulator) error { | ||||||
| 
 | 
 | ||||||
| 		total := totalCpuTime(cts) | 		total := totalCpuTime(cts) | ||||||
| 
 | 
 | ||||||
| 		// Add total cpu numbers
 | 		// Add cpu time metrics
 | ||||||
| 		add(acc, "time_user", cts.User, tags) | 		fields := map[string]interface{}{ | ||||||
| 		add(acc, "time_system", cts.System, tags) | 			"time_user":       cts.User, | ||||||
| 		add(acc, "time_idle", cts.Idle, tags) | 			"time_system":     cts.System, | ||||||
| 		add(acc, "time_nice", cts.Nice, tags) | 			"time_idle":       cts.Idle, | ||||||
| 		add(acc, "time_iowait", cts.Iowait, tags) | 			"time_nice":       cts.Nice, | ||||||
| 		add(acc, "time_irq", cts.Irq, tags) | 			"time_iowait":     cts.Iowait, | ||||||
| 		add(acc, "time_softirq", cts.Softirq, tags) | 			"time_irq":        cts.Irq, | ||||||
| 		add(acc, "time_steal", cts.Steal, tags) | 			"time_softirq":    cts.Softirq, | ||||||
| 		add(acc, "time_guest", cts.Guest, tags) | 			"time_steal":      cts.Steal, | ||||||
| 		add(acc, "time_guest_nice", cts.GuestNice, tags) | 			"time_guest":      cts.Guest, | ||||||
|  | 			"time_guest_nice": cts.GuestNice, | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Add in percentage
 | 		// Add in percentage
 | ||||||
| 		if len(s.lastStats) == 0 { | 		if len(s.lastStats) == 0 { | ||||||
| 			// If it's the 1st gather, can't get CPU stats yet
 | 			acc.AddFields("cpu", fields, tags, now) | ||||||
|  | 			// If it's the 1st gather, can't get CPU Usage stats yet
 | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		lastCts := s.lastStats[i] | 		lastCts := s.lastStats[i] | ||||||
|  | @ -81,17 +86,17 @@ func (s *CPUStats) Gather(acc plugins.Accumulator) error { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		add(acc, "usage_user", 100*(cts.User-lastCts.User)/totalDelta, tags) | 		fields["usage_user"] = 100 * (cts.User - lastCts.User) / totalDelta | ||||||
| 		add(acc, "usage_system", 100*(cts.System-lastCts.System)/totalDelta, tags) | 		fields["usage_system"] = 100 * (cts.System - lastCts.System) / totalDelta | ||||||
| 		add(acc, "usage_idle", 100*(cts.Idle-lastCts.Idle)/totalDelta, tags) | 		fields["usage_idle"] = 100 * (cts.Idle - lastCts.Idle) / totalDelta | ||||||
| 		add(acc, "usage_nice", 100*(cts.Nice-lastCts.Nice)/totalDelta, tags) | 		fields["usage_nice"] = 100 * (cts.Nice - lastCts.Nice) / totalDelta | ||||||
| 		add(acc, "usage_iowait", 100*(cts.Iowait-lastCts.Iowait)/totalDelta, tags) | 		fields["usage_iowait"] = 100 * (cts.Iowait - lastCts.Iowait) / totalDelta | ||||||
| 		add(acc, "usage_irq", 100*(cts.Irq-lastCts.Irq)/totalDelta, tags) | 		fields["usage_irq"] = 100 * (cts.Irq - lastCts.Irq) / totalDelta | ||||||
| 		add(acc, "usage_softirq", 100*(cts.Softirq-lastCts.Softirq)/totalDelta, tags) | 		fields["usage_softirq"] = 100 * (cts.Softirq - lastCts.Softirq) / totalDelta | ||||||
| 		add(acc, "usage_steal", 100*(cts.Steal-lastCts.Steal)/totalDelta, tags) | 		fields["usage_steal"] = 100 * (cts.Steal - lastCts.Steal) / totalDelta | ||||||
| 		add(acc, "usage_guest", 100*(cts.Guest-lastCts.Guest)/totalDelta, tags) | 		fields["usage_guest"] = 100 * (cts.Guest - lastCts.Guest) / totalDelta | ||||||
| 		add(acc, "usage_guest_nice", 100*(cts.GuestNice-lastCts.GuestNice)/totalDelta, tags) | 		fields["usage_guest_nice"] = 100 * (cts.GuestNice - lastCts.GuestNice) / totalDelta | ||||||
| 
 | 		acc.AddFields("cpu", fields, tags, now) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	s.lastStats = times | 	s.lastStats = times | ||||||
|  |  | ||||||
|  | @ -0,0 +1,106 @@ | ||||||
|  | package system | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/influxdb/telegraf/testutil" | ||||||
|  | 	"github.com/shirou/gopsutil/cpu" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestCPUStats(t *testing.T) { | ||||||
|  | 	var mps MockPS | ||||||
|  | 	defer mps.AssertExpectations(t) | ||||||
|  | 	var acc testutil.Accumulator | ||||||
|  | 
 | ||||||
|  | 	cts := cpu.CPUTimesStat{ | ||||||
|  | 		CPU:       "cpu0", | ||||||
|  | 		User:      3.1, | ||||||
|  | 		System:    8.2, | ||||||
|  | 		Idle:      80.1, | ||||||
|  | 		Nice:      1.3, | ||||||
|  | 		Iowait:    0.2, | ||||||
|  | 		Irq:       0.1, | ||||||
|  | 		Softirq:   0.11, | ||||||
|  | 		Steal:     0.0511, | ||||||
|  | 		Guest:     8.1, | ||||||
|  | 		GuestNice: 0.324, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cts2 := cpu.CPUTimesStat{ | ||||||
|  | 		CPU:       "cpu0", | ||||||
|  | 		User:      11.4,     // increased by 8.3
 | ||||||
|  | 		System:    10.9,     // increased by 2.7
 | ||||||
|  | 		Idle:      158.8699, // increased by 78.7699 (for total increase of 100)
 | ||||||
|  | 		Nice:      2.5,      // increased by 1.2
 | ||||||
|  | 		Iowait:    0.7,      // increased by 0.5
 | ||||||
|  | 		Irq:       1.2,      // increased by 1.1
 | ||||||
|  | 		Softirq:   0.31,     // increased by 0.2
 | ||||||
|  | 		Steal:     0.2812,   // increased by 0.0001
 | ||||||
|  | 		Guest:     12.9,     // increased by 4.8
 | ||||||
|  | 		GuestNice: 2.524,    // increased by 2.2
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil) | ||||||
|  | 
 | ||||||
|  | 	cs := NewCPUStats(&mps) | ||||||
|  | 
 | ||||||
|  | 	cputags := map[string]string{ | ||||||
|  | 		"cpu": "cpu0", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err := cs.Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	numCPUPoints := len(acc.Points) | ||||||
|  | 
 | ||||||
|  | 	expectedCPUPoints := 10 | ||||||
|  | 	assert.Equal(t, expectedCPUPoints, numCPUPoints) | ||||||
|  | 
 | ||||||
|  | 	// Computed values are checked with delta > 0 becasue of floating point arithmatic
 | ||||||
|  | 	// imprecision
 | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_user", 3.1, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_system", 8.2, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_idle", 80.1, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_nice", 1.3, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_iowait", 0.2, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_irq", 0.1, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_softirq", 0.11, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_steal", 0.0511, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_guest", 8.1, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_guest_nice", 0.324, 0, cputags) | ||||||
|  | 
 | ||||||
|  | 	mps2 := MockPS{} | ||||||
|  | 	mps2.On("CPUTimes").Return([]cpu.CPUTimesStat{cts2}, nil) | ||||||
|  | 	cs.ps = &mps2 | ||||||
|  | 
 | ||||||
|  | 	// Should have added cpu percentages too
 | ||||||
|  | 	err = cs.Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	numCPUPoints = len(acc.Points) - numCPUPoints | ||||||
|  | 	expectedCPUPoints = 20 | ||||||
|  | 	assert.Equal(t, expectedCPUPoints, numCPUPoints) | ||||||
|  | 
 | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_user", 11.4, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_system", 10.9, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_idle", 158.8699, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_nice", 2.5, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_iowait", 0.7, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_irq", 1.2, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_softirq", 0.31, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_steal", 0.2812, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_guest", 12.9, 0, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "time_guest_nice", 2.524, 0, cputags) | ||||||
|  | 
 | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_user", 8.3, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_system", 2.7, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_idle", 78.7699, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_nice", 1.2, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_iowait", 0.5, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_irq", 1.1, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_softirq", 0.2, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_steal", 0.2301, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_guest", 4.8, 0.0005, cputags) | ||||||
|  | 	assertContainsTaggedFloat(t, &acc, "usage_guest_nice", 2.2, 0.0005, cputags) | ||||||
|  | } | ||||||
|  | @ -50,12 +50,15 @@ func (s *DiskStats) Gather(acc plugins.Accumulator) error { | ||||||
| 			"path":   du.Path, | 			"path":   du.Path, | ||||||
| 			"fstype": du.Fstype, | 			"fstype": du.Fstype, | ||||||
| 		} | 		} | ||||||
| 		acc.Add("total", du.Total, tags) | 		fields := map[string]interface{}{ | ||||||
| 		acc.Add("free", du.Free, tags) | 			"total":        du.Total, | ||||||
| 		acc.Add("used", du.Total-du.Free, tags) | 			"free":         du.Free, | ||||||
| 		acc.Add("inodes_total", du.InodesTotal, tags) | 			"used":         du.Total - du.Free, | ||||||
| 		acc.Add("inodes_free", du.InodesFree, tags) | 			"inodes_total": du.InodesTotal, | ||||||
| 		acc.Add("inodes_used", du.InodesTotal-du.InodesFree, tags) | 			"inodes_free":  du.InodesFree, | ||||||
|  | 			"inodes_used":  du.InodesTotal - du.InodesFree, | ||||||
|  | 		} | ||||||
|  | 		acc.AddFields("disk", fields, tags) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -115,13 +118,16 @@ func (s *DiskIOStats) Gather(acc plugins.Accumulator) error { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		acc.Add("reads", io.ReadCount, tags) | 		fields := map[string]interface{}{ | ||||||
| 		acc.Add("writes", io.WriteCount, tags) | 			"reads":       io.ReadCount, | ||||||
| 		acc.Add("read_bytes", io.ReadBytes, tags) | 			"writes":      io.WriteCount, | ||||||
| 		acc.Add("write_bytes", io.WriteBytes, tags) | 			"read_bytes":  io.ReadBytes, | ||||||
| 		acc.Add("read_time", io.ReadTime, tags) | 			"write_bytes": io.WriteBytes, | ||||||
| 		acc.Add("write_time", io.WriteTime, tags) | 			"read_time":   io.ReadTime, | ||||||
| 		acc.Add("io_time", io.IoTime, tags) | 			"write_time":  io.WriteTime, | ||||||
|  | 			"io_time":     io.IoTime, | ||||||
|  | 		} | ||||||
|  | 		acc.AddFields("diskio", fields, tags) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -132,7 +138,7 @@ func init() { | ||||||
| 		return &DiskStats{ps: &systemPS{}} | 		return &DiskStats{ps: &systemPS{}} | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	plugins.Add("io", func() plugins.Plugin { | 	plugins.Add("diskio", func() plugins.Plugin { | ||||||
| 		return &DiskIOStats{ps: &systemPS{}} | 		return &DiskIOStats{ps: &systemPS{}} | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,161 @@ | ||||||
|  | package system | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/influxdb/telegraf/testutil" | ||||||
|  | 	"github.com/shirou/gopsutil/disk" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestDiskStats(t *testing.T) { | ||||||
|  | 	var mps MockPS | ||||||
|  | 	defer mps.AssertExpectations(t) | ||||||
|  | 	var acc testutil.Accumulator | ||||||
|  | 	var err error | ||||||
|  | 
 | ||||||
|  | 	du := []*disk.DiskUsageStat{ | ||||||
|  | 		{ | ||||||
|  | 			Path:        "/", | ||||||
|  | 			Fstype:      "ext4", | ||||||
|  | 			Total:       128, | ||||||
|  | 			Free:        23, | ||||||
|  | 			InodesTotal: 1234, | ||||||
|  | 			InodesFree:  234, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Path:        "/home", | ||||||
|  | 			Fstype:      "ext4", | ||||||
|  | 			Total:       256, | ||||||
|  | 			Free:        46, | ||||||
|  | 			InodesTotal: 2468, | ||||||
|  | 			InodesFree:  468, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("DiskUsage").Return(du, nil) | ||||||
|  | 
 | ||||||
|  | 	err = (&DiskStats{ps: &mps}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	numDiskPoints := len(acc.Points) | ||||||
|  | 	expectedAllDiskPoints := 12 | ||||||
|  | 	assert.Equal(t, expectedAllDiskPoints, numDiskPoints) | ||||||
|  | 
 | ||||||
|  | 	tags1 := map[string]string{ | ||||||
|  | 		"path":   "/", | ||||||
|  | 		"fstype": "ext4", | ||||||
|  | 	} | ||||||
|  | 	tags2 := map[string]string{ | ||||||
|  | 		"path":   "/home", | ||||||
|  | 		"fstype": "ext4", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("total", uint64(128), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("used", uint64(105), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("free", uint64(23), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_total", uint64(1234), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_free", uint64(234), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_used", uint64(1000), tags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("total", uint64(256), tags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("used", uint64(210), tags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("free", uint64(46), tags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_total", uint64(2468), tags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_free", uint64(468), tags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("inodes_used", uint64(2000), tags2)) | ||||||
|  | 
 | ||||||
|  | 	// We expect 6 more DiskPoints to show up with an explicit match on "/"
 | ||||||
|  | 	// and /home not matching the /dev in Mountpoints
 | ||||||
|  | 	err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/dev"}}).Gather(&acc) | ||||||
|  | 	assert.Equal(t, expectedAllDiskPoints+6, len(acc.Points)) | ||||||
|  | 
 | ||||||
|  | 	// We should see all the diskpoints as Mountpoints includes both
 | ||||||
|  | 	// / and /home
 | ||||||
|  | 	err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/home"}}).Gather(&acc) | ||||||
|  | 	assert.Equal(t, 2*expectedAllDiskPoints+6, len(acc.Points)) | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestDiskIOStats(t *testing.T) { | ||||||
|  | 	var mps MockPS | ||||||
|  | 	defer mps.AssertExpectations(t) | ||||||
|  | 	var acc testutil.Accumulator | ||||||
|  | 	var err error | ||||||
|  | 
 | ||||||
|  | 	diskio1 := disk.DiskIOCountersStat{ | ||||||
|  | 
 | ||||||
|  | 		ReadCount:    888, | ||||||
|  | 		WriteCount:   5341, | ||||||
|  | 		ReadBytes:    100000, | ||||||
|  | 		WriteBytes:   200000, | ||||||
|  | 		ReadTime:     7123, | ||||||
|  | 		WriteTime:    9087, | ||||||
|  | 		Name:         "sda1", | ||||||
|  | 		IoTime:       123552, | ||||||
|  | 		SerialNumber: "ab-123-ad", | ||||||
|  | 	} | ||||||
|  | 	diskio2 := disk.DiskIOCountersStat{ | ||||||
|  | 		ReadCount:    444, | ||||||
|  | 		WriteCount:   2341, | ||||||
|  | 		ReadBytes:    200000, | ||||||
|  | 		WriteBytes:   400000, | ||||||
|  | 		ReadTime:     3123, | ||||||
|  | 		WriteTime:    6087, | ||||||
|  | 		Name:         "sdb1", | ||||||
|  | 		IoTime:       246552, | ||||||
|  | 		SerialNumber: "bb-123-ad", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("DiskIO").Return( | ||||||
|  | 		map[string]disk.DiskIOCountersStat{"sda1": diskio1, "sdb1": diskio2}, | ||||||
|  | 		nil) | ||||||
|  | 
 | ||||||
|  | 	err = (&DiskIOStats{ps: &mps}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	numDiskIOPoints := len(acc.Points) | ||||||
|  | 	expectedAllDiskIOPoints := 14 | ||||||
|  | 	assert.Equal(t, expectedAllDiskIOPoints, numDiskIOPoints) | ||||||
|  | 
 | ||||||
|  | 	dtags1 := map[string]string{ | ||||||
|  | 		"name":   "sda1", | ||||||
|  | 		"serial": "ab-123-ad", | ||||||
|  | 	} | ||||||
|  | 	dtags2 := map[string]string{ | ||||||
|  | 		"name":   "sdb1", | ||||||
|  | 		"serial": "bb-123-ad", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("reads", uint64(888), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("writes", uint64(5341), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(100000), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(200000), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(7123), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(9087), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(123552), dtags1)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags2)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags2)) | ||||||
|  | 
 | ||||||
|  | 	// We expect 7 more DiskIOPoints to show up with an explicit match on "sdb1"
 | ||||||
|  | 	// and serial should be missing from the tags with SkipSerialNumber set
 | ||||||
|  | 	err = (&DiskIOStats{ps: &mps, Devices: []string{"sdb1"}, SkipSerialNumber: true}).Gather(&acc) | ||||||
|  | 	assert.Equal(t, expectedAllDiskIOPoints+7, len(acc.Points)) | ||||||
|  | 
 | ||||||
|  | 	dtags3 := map[string]string{ | ||||||
|  | 		"name": "sdb1", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags3)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags3)) | ||||||
|  | } | ||||||
|  | @ -36,44 +36,47 @@ func (s *DockerStats) Gather(acc plugins.Accumulator) error { | ||||||
| 
 | 
 | ||||||
| 		cts := cont.CPU | 		cts := cont.CPU | ||||||
| 
 | 
 | ||||||
| 		acc.Add("user", cts.User, tags) | 		fields := map[string]interface{}{ | ||||||
| 		acc.Add("system", cts.System, tags) | 			"user":       cts.User, | ||||||
| 		acc.Add("idle", cts.Idle, tags) | 			"system":     cts.System, | ||||||
| 		acc.Add("nice", cts.Nice, tags) | 			"idle":       cts.Idle, | ||||||
| 		acc.Add("iowait", cts.Iowait, tags) | 			"nice":       cts.Nice, | ||||||
| 		acc.Add("irq", cts.Irq, tags) | 			"iowait":     cts.Iowait, | ||||||
| 		acc.Add("softirq", cts.Softirq, tags) | 			"irq":        cts.Irq, | ||||||
| 		acc.Add("steal", cts.Steal, tags) | 			"softirq":    cts.Softirq, | ||||||
| 		acc.Add("guest", cts.Guest, tags) | 			"steal":      cts.Steal, | ||||||
| 		acc.Add("guest_nice", cts.GuestNice, tags) | 			"guest":      cts.Guest, | ||||||
|  | 			"guest_nice": cts.GuestNice, | ||||||
| 
 | 
 | ||||||
| 		acc.Add("cache", cont.Mem.Cache, tags) | 			"cache":                  cont.Mem.Cache, | ||||||
| 		acc.Add("rss", cont.Mem.RSS, tags) | 			"rss":                    cont.Mem.RSS, | ||||||
| 		acc.Add("rss_huge", cont.Mem.RSSHuge, tags) | 			"rss_huge":               cont.Mem.RSSHuge, | ||||||
| 		acc.Add("mapped_file", cont.Mem.MappedFile, tags) | 			"mapped_file":            cont.Mem.MappedFile, | ||||||
| 		acc.Add("swap_in", cont.Mem.Pgpgin, tags) | 			"swap_in":                cont.Mem.Pgpgin, | ||||||
| 		acc.Add("swap_out", cont.Mem.Pgpgout, tags) | 			"swap_out":               cont.Mem.Pgpgout, | ||||||
| 		acc.Add("page_fault", cont.Mem.Pgfault, tags) | 			"page_fault":             cont.Mem.Pgfault, | ||||||
| 		acc.Add("page_major_fault", cont.Mem.Pgmajfault, tags) | 			"page_major_fault":       cont.Mem.Pgmajfault, | ||||||
| 		acc.Add("inactive_anon", cont.Mem.InactiveAnon, tags) | 			"inactive_anon":          cont.Mem.InactiveAnon, | ||||||
| 		acc.Add("active_anon", cont.Mem.ActiveAnon, tags) | 			"active_anon":            cont.Mem.ActiveAnon, | ||||||
| 		acc.Add("inactive_file", cont.Mem.InactiveFile, tags) | 			"inactive_file":          cont.Mem.InactiveFile, | ||||||
| 		acc.Add("active_file", cont.Mem.ActiveFile, tags) | 			"active_file":            cont.Mem.ActiveFile, | ||||||
| 		acc.Add("unevictable", cont.Mem.Unevictable, tags) | 			"unevictable":            cont.Mem.Unevictable, | ||||||
| 		acc.Add("memory_limit", cont.Mem.HierarchicalMemoryLimit, tags) | 			"memory_limit":           cont.Mem.HierarchicalMemoryLimit, | ||||||
| 		acc.Add("total_cache", cont.Mem.TotalCache, tags) | 			"total_cache":            cont.Mem.TotalCache, | ||||||
| 		acc.Add("total_rss", cont.Mem.TotalRSS, tags) | 			"total_rss":              cont.Mem.TotalRSS, | ||||||
| 		acc.Add("total_rss_huge", cont.Mem.TotalRSSHuge, tags) | 			"total_rss_huge":         cont.Mem.TotalRSSHuge, | ||||||
| 		acc.Add("total_mapped_file", cont.Mem.TotalMappedFile, tags) | 			"total_mapped_file":      cont.Mem.TotalMappedFile, | ||||||
| 		acc.Add("total_swap_in", cont.Mem.TotalPgpgIn, tags) | 			"total_swap_in":          cont.Mem.TotalPgpgIn, | ||||||
| 		acc.Add("total_swap_out", cont.Mem.TotalPgpgOut, tags) | 			"total_swap_out":         cont.Mem.TotalPgpgOut, | ||||||
| 		acc.Add("total_page_fault", cont.Mem.TotalPgFault, tags) | 			"total_page_fault":       cont.Mem.TotalPgFault, | ||||||
| 		acc.Add("total_page_major_fault", cont.Mem.TotalPgMajFault, tags) | 			"total_page_major_fault": cont.Mem.TotalPgMajFault, | ||||||
| 		acc.Add("total_inactive_anon", cont.Mem.TotalInactiveAnon, tags) | 			"total_inactive_anon":    cont.Mem.TotalInactiveAnon, | ||||||
| 		acc.Add("total_active_anon", cont.Mem.TotalActiveAnon, tags) | 			"total_active_anon":      cont.Mem.TotalActiveAnon, | ||||||
| 		acc.Add("total_inactive_file", cont.Mem.TotalInactiveFile, tags) | 			"total_inactive_file":    cont.Mem.TotalInactiveFile, | ||||||
| 		acc.Add("total_active_file", cont.Mem.TotalActiveFile, tags) | 			"total_active_file":      cont.Mem.TotalActiveFile, | ||||||
| 		acc.Add("total_unevictable", cont.Mem.TotalUnevictable, tags) | 			"total_unevictable":      cont.Mem.TotalUnevictable, | ||||||
|  | 		} | ||||||
|  | 		acc.AddFields("docker", fields, tags) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
|  | @ -22,18 +22,17 @@ func (s *MemStats) Gather(acc plugins.Accumulator) error { | ||||||
| 		return fmt.Errorf("error getting virtual memory info: %s", err) | 		return fmt.Errorf("error getting virtual memory info: %s", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	vmtags := map[string]string(nil) | 	fields := map[string]interface{}{ | ||||||
| 
 | 		"total":             vm.Total, | ||||||
| 	acc.Add("total", vm.Total, vmtags) | 		"available":         vm.Available, | ||||||
| 	acc.Add("available", vm.Available, vmtags) | 		"used":              vm.Used, | ||||||
| 	acc.Add("used", vm.Used, vmtags) | 		"free":              vm.Free, | ||||||
| 	acc.Add("free", vm.Free, vmtags) | 		"cached":            vm.Cached, | ||||||
| 	acc.Add("cached", vm.Cached, vmtags) | 		"buffered":          vm.Buffers, | ||||||
| 	acc.Add("buffered", vm.Buffers, vmtags) | 		"used_percent":      100 * float64(vm.Used) / float64(vm.Total), | ||||||
| 	acc.Add("used_percent", 100*float64(vm.Used)/float64(vm.Total), vmtags) | 		"available_percent": 100 * float64(vm.Available) / float64(vm.Total), | ||||||
| 	acc.Add("available_percent", | 	} | ||||||
| 		100*float64(vm.Available)/float64(vm.Total), | 	acc.AddFields("mem", fields, nil) | ||||||
| 		vmtags) |  | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | @ -54,14 +53,15 @@ func (s *SwapStats) Gather(acc plugins.Accumulator) error { | ||||||
| 		return fmt.Errorf("error getting swap memory info: %s", err) | 		return fmt.Errorf("error getting swap memory info: %s", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	swaptags := map[string]string(nil) | 	fields := map[string]interface{}{ | ||||||
| 
 | 		"total":        swap.Total, | ||||||
| 	acc.Add("total", swap.Total, swaptags) | 		"used":         swap.Used, | ||||||
| 	acc.Add("used", swap.Used, swaptags) | 		"free":         swap.Free, | ||||||
| 	acc.Add("free", swap.Free, swaptags) | 		"used_percent": swap.UsedPercent, | ||||||
| 	acc.Add("used_percent", swap.UsedPercent, swaptags) | 		"in":           swap.Sin, | ||||||
| 	acc.Add("in", swap.Sin, swaptags) | 		"out":          swap.Sout, | ||||||
| 	acc.Add("out", swap.Sout, swaptags) | 	} | ||||||
|  | 	acc.AddFields("swap", fields, nil) | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,73 @@ | ||||||
|  | package system | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/influxdb/telegraf/testutil" | ||||||
|  | 	"github.com/shirou/gopsutil/mem" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestMemStats(t *testing.T) { | ||||||
|  | 	var mps MockPS | ||||||
|  | 	var err error | ||||||
|  | 	defer mps.AssertExpectations(t) | ||||||
|  | 	var acc testutil.Accumulator | ||||||
|  | 
 | ||||||
|  | 	vms := &mem.VirtualMemoryStat{ | ||||||
|  | 		Total:     12400, | ||||||
|  | 		Available: 7600, | ||||||
|  | 		Used:      5000, | ||||||
|  | 		Free:      1235, | ||||||
|  | 		// Active:      8134,
 | ||||||
|  | 		// Inactive:    1124,
 | ||||||
|  | 		// Buffers:     771,
 | ||||||
|  | 		// Cached:      4312,
 | ||||||
|  | 		// Wired:       134,
 | ||||||
|  | 		// Shared:      2142,
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("VMStat").Return(vms, nil) | ||||||
|  | 
 | ||||||
|  | 	sms := &mem.SwapMemoryStat{ | ||||||
|  | 		Total:       8123, | ||||||
|  | 		Used:        1232, | ||||||
|  | 		Free:        6412, | ||||||
|  | 		UsedPercent: 12.2, | ||||||
|  | 		Sin:         7, | ||||||
|  | 		Sout:        830, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("SwapStat").Return(sms, nil) | ||||||
|  | 
 | ||||||
|  | 	err = (&MemStats{&mps}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	vmtags := map[string]string(nil) | ||||||
|  | 
 | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("total", uint64(12400), vmtags)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("available", uint64(7600), vmtags)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("used", uint64(5000), vmtags)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("available_percent", | ||||||
|  | 		float64(7600)/float64(12400)*100, | ||||||
|  | 		vmtags)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("used_percent", | ||||||
|  | 		float64(5000)/float64(12400)*100, | ||||||
|  | 		vmtags)) | ||||||
|  | 	assert.True(t, acc.CheckTaggedValue("free", uint64(1235), vmtags)) | ||||||
|  | 
 | ||||||
|  | 	acc.Points = nil | ||||||
|  | 
 | ||||||
|  | 	err = (&SwapStats{&mps}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	swaptags := map[string]string(nil) | ||||||
|  | 
 | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("total", uint64(8123), swaptags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("used", uint64(1232), swaptags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("used_percent", float64(12.2), swaptags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("free", uint64(6412), swaptags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("in", uint64(7), swaptags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("out", uint64(830), swaptags)) | ||||||
|  | } | ||||||
|  | @ -70,14 +70,17 @@ func (s *NetIOStats) Gather(acc plugins.Accumulator) error { | ||||||
| 			"interface": io.Name, | 			"interface": io.Name, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		acc.Add("bytes_sent", io.BytesSent, tags) | 		fields := map[string]interface{}{ | ||||||
| 		acc.Add("bytes_recv", io.BytesRecv, tags) | 			"bytes_sent":   io.BytesSent, | ||||||
| 		acc.Add("packets_sent", io.PacketsSent, tags) | 			"bytes_recv":   io.BytesRecv, | ||||||
| 		acc.Add("packets_recv", io.PacketsRecv, tags) | 			"packets_sent": io.PacketsSent, | ||||||
| 		acc.Add("err_in", io.Errin, tags) | 			"packets_recv": io.PacketsRecv, | ||||||
| 		acc.Add("err_out", io.Errout, tags) | 			"err_in":       io.Errin, | ||||||
| 		acc.Add("drop_in", io.Dropin, tags) | 			"err_out":      io.Errout, | ||||||
| 		acc.Add("drop_out", io.Dropout, tags) | 			"drop_in":      io.Dropin, | ||||||
|  | 			"drop_out":     io.Dropout, | ||||||
|  | 		} | ||||||
|  | 		acc.AddFields("net", fields, tags) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Get system wide stats for different network protocols
 | 	// Get system wide stats for different network protocols
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,88 @@ | ||||||
|  | package system | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/influxdb/telegraf/testutil" | ||||||
|  | 	"github.com/shirou/gopsutil/net" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestNetStats(t *testing.T) { | ||||||
|  | 	var mps MockPS | ||||||
|  | 	var err error | ||||||
|  | 	defer mps.AssertExpectations(t) | ||||||
|  | 	var acc testutil.Accumulator | ||||||
|  | 
 | ||||||
|  | 	netio := net.NetIOCountersStat{ | ||||||
|  | 		Name:        "eth0", | ||||||
|  | 		BytesSent:   1123, | ||||||
|  | 		BytesRecv:   8734422, | ||||||
|  | 		PacketsSent: 781, | ||||||
|  | 		PacketsRecv: 23456, | ||||||
|  | 		Errin:       832, | ||||||
|  | 		Errout:      8, | ||||||
|  | 		Dropin:      7, | ||||||
|  | 		Dropout:     1, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("NetIO").Return([]net.NetIOCountersStat{netio}, nil) | ||||||
|  | 
 | ||||||
|  | 	netprotos := []net.NetProtoCountersStat{ | ||||||
|  | 		net.NetProtoCountersStat{ | ||||||
|  | 			Protocol: "Udp", | ||||||
|  | 			Stats: map[string]int64{ | ||||||
|  | 				"InDatagrams": 4655, | ||||||
|  | 				"NoPorts":     892592, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	mps.On("NetProto").Return(netprotos, nil) | ||||||
|  | 
 | ||||||
|  | 	netstats := []net.NetConnectionStat{ | ||||||
|  | 		net.NetConnectionStat{ | ||||||
|  | 			Type: syscall.SOCK_DGRAM, | ||||||
|  | 		}, | ||||||
|  | 		net.NetConnectionStat{ | ||||||
|  | 			Status: "ESTABLISHED", | ||||||
|  | 		}, | ||||||
|  | 		net.NetConnectionStat{ | ||||||
|  | 			Status: "ESTABLISHED", | ||||||
|  | 		}, | ||||||
|  | 		net.NetConnectionStat{ | ||||||
|  | 			Status: "CLOSE", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mps.On("NetConnections").Return(netstats, nil) | ||||||
|  | 
 | ||||||
|  | 	err = (&NetIOStats{ps: &mps, skipChecks: true}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	ntags := map[string]string{ | ||||||
|  | 		"interface": "eth0", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("bytes_sent", uint64(1123), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("bytes_recv", uint64(8734422), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("packets_sent", uint64(781), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("packets_recv", uint64(23456), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("err_in", uint64(832), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("err_out", uint64(8), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("drop_in", uint64(7), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("drop_out", uint64(1), ntags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateValue("udp_noports", int64(892592))) | ||||||
|  | 	assert.NoError(t, acc.ValidateValue("udp_indatagrams", int64(4655))) | ||||||
|  | 
 | ||||||
|  | 	acc.Points = nil | ||||||
|  | 
 | ||||||
|  | 	err = (&NetStats{&mps}).Gather(&acc) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	netstattags := map[string]string(nil) | ||||||
|  | 
 | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("tcp_established", 2, netstattags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("tcp_close", 1, netstattags)) | ||||||
|  | 	assert.NoError(t, acc.ValidateTaggedValue("udp_socket", 1, netstattags)) | ||||||
|  | } | ||||||
|  | @ -42,19 +42,23 @@ func (s *NetStats) Gather(acc plugins.Accumulator) error { | ||||||
| 		} | 		} | ||||||
| 		counts[netcon.Status] = c + 1 | 		counts[netcon.Status] = c + 1 | ||||||
| 	} | 	} | ||||||
| 	acc.Add("tcp_established", counts["ESTABLISHED"], tags) | 
 | ||||||
| 	acc.Add("tcp_syn_sent", counts["SYN_SENT"], tags) | 	fields := map[string]interface{}{ | ||||||
| 	acc.Add("tcp_syn_recv", counts["SYN_RECV"], tags) | 		"tcp_established": counts["ESTABLISHED"], | ||||||
| 	acc.Add("tcp_fin_wait1", counts["FIN_WAIT1"], tags) | 		"tcp_syn_sent":    counts["SYN_SENT"], | ||||||
| 	acc.Add("tcp_fin_wait2", counts["FIN_WAIT2"], tags) | 		"tcp_syn_recv":    counts["SYN_RECV"], | ||||||
| 	acc.Add("tcp_time_wait", counts["TIME_WAIT"], tags) | 		"tcp_fin_wait1":   counts["FIN_WAIT1"], | ||||||
| 	acc.Add("tcp_close", counts["CLOSE"], tags) | 		"tcp_fin_wait2":   counts["FIN_WAIT2"], | ||||||
| 	acc.Add("tcp_close_wait", counts["CLOSE_WAIT"], tags) | 		"tcp_time_wait":   counts["TIME_WAIT"], | ||||||
| 	acc.Add("tcp_last_ack", counts["LAST_ACK"], tags) | 		"tcp_close":       counts["CLOSE"], | ||||||
| 	acc.Add("tcp_listen", counts["LISTEN"], tags) | 		"tcp_close_wait":  counts["CLOSE_WAIT"], | ||||||
| 	acc.Add("tcp_closing", counts["CLOSING"], tags) | 		"tcp_last_ack":    counts["LAST_ACK"], | ||||||
| 	acc.Add("tcp_none", counts["NONE"], tags) | 		"tcp_listen":      counts["LISTEN"], | ||||||
| 	acc.Add("udp_socket", counts["UDP"], tags) | 		"tcp_closing":     counts["CLOSING"], | ||||||
|  | 		"tcp_none":        counts["NONE"], | ||||||
|  | 		"udp_socket":      counts["UDP"], | ||||||
|  | 	} | ||||||
|  | 	acc.AddFields("netstat", fields, tags) | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,12 +1,16 @@ | ||||||
| package system | package system | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	gonet "net" | 	gonet "net" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/influxdb/telegraf/internal" | 	"github.com/influxdb/telegraf/internal" | ||||||
| 	"github.com/influxdb/telegraf/plugins" | 	"github.com/influxdb/telegraf/plugins" | ||||||
|  | 	"github.com/influxdb/telegraf/testutil" | ||||||
| 
 | 
 | ||||||
| 	dc "github.com/fsouza/go-dockerclient" | 	dc "github.com/fsouza/go-dockerclient" | ||||||
| 	"github.com/shirou/gopsutil/cpu" | 	"github.com/shirou/gopsutil/cpu" | ||||||
|  | @ -14,6 +18,8 @@ import ( | ||||||
| 	"github.com/shirou/gopsutil/docker" | 	"github.com/shirou/gopsutil/docker" | ||||||
| 	"github.com/shirou/gopsutil/mem" | 	"github.com/shirou/gopsutil/mem" | ||||||
| 	"github.com/shirou/gopsutil/net" | 	"github.com/shirou/gopsutil/net" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type DockerContainerStat struct { | type DockerContainerStat struct { | ||||||
|  | @ -166,3 +172,49 @@ func (s *systemPS) DockerStat() ([]*DockerContainerStat, error) { | ||||||
| 
 | 
 | ||||||
| 	return stats, nil | 	return stats, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Asserts that a given accumulator contains a measurment of type float64 with
 | ||||||
|  | // specific tags within a certain distance of a given expected value. Asserts a failure
 | ||||||
|  | // if the measurement is of the wrong type, or if no matching measurements are found
 | ||||||
|  | //
 | ||||||
|  | // Paramaters:
 | ||||||
|  | //     t *testing.T            : Testing object to use
 | ||||||
|  | //     acc testutil.Accumulator: Accumulator to examine
 | ||||||
|  | //     measurement string      : Name of the measurement to examine
 | ||||||
|  | //     expectedValue float64   : Value to search for within the measurement
 | ||||||
|  | //     delta float64           : Maximum acceptable distance of an accumulated value
 | ||||||
|  | //                               from the expectedValue parameter. Useful when
 | ||||||
|  | //                               floating-point arithmatic imprecision makes looking
 | ||||||
|  | //                               for an exact match impractical
 | ||||||
|  | //     tags map[string]string  : Tag set the found measurement must have. Set to nil to
 | ||||||
|  | //                               ignore the tag set.
 | ||||||
|  | func assertContainsTaggedFloat( | ||||||
|  | 	t *testing.T, | ||||||
|  | 	acc *testutil.Accumulator, | ||||||
|  | 	measurement string, | ||||||
|  | 	expectedValue float64, | ||||||
|  | 	delta float64, | ||||||
|  | 	tags map[string]string, | ||||||
|  | ) { | ||||||
|  | 	var actualValue float64 | ||||||
|  | 	for _, pt := range acc.Points { | ||||||
|  | 		if pt.Measurement == measurement { | ||||||
|  | 			if (tags == nil) || reflect.DeepEqual(pt.Tags, tags) { | ||||||
|  | 				if value, ok := pt.Fields["value"].(float64); ok { | ||||||
|  | 					actualValue = value | ||||||
|  | 					if (value >= expectedValue-delta) && (value <= expectedValue+delta) { | ||||||
|  | 						// Found the point, return without failing
 | ||||||
|  | 						return | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					assert.Fail(t, fmt.Sprintf("Measurement \"%s\" does not have type float64", | ||||||
|  | 						measurement)) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	msg := fmt.Sprintf("Could not find measurement \"%s\" with requested tags within %f of %f, Actual: %f", | ||||||
|  | 		measurement, delta, expectedValue, actualValue) | ||||||
|  | 	assert.Fail(t, msg) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -37,11 +37,14 @@ func (_ *SystemStats) Gather(acc plugins.Accumulator) error { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	acc.Add("load1", loadavg.Load1, nil) | 	fields := map[string]interface{}{ | ||||||
| 	acc.Add("load5", loadavg.Load5, nil) | 		"load1":         loadavg.Load1, | ||||||
| 	acc.Add("load15", loadavg.Load15, nil) | 		"load5":         loadavg.Load5, | ||||||
| 	acc.Add("uptime", float64(hostinfo.Uptime), nil) | 		"load15":        loadavg.Load15, | ||||||
| 	acc.Add("uptime_format", format_uptime(hostinfo.Uptime), nil) | 		"uptime":        float64(hostinfo.Uptime), | ||||||
|  | 		"uptime_format": format_uptime(hostinfo.Uptime), | ||||||
|  | 	} | ||||||
|  | 	acc.AddFields("system", fields, nil) | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,426 +0,0 @@ | ||||||
| package system |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"reflect" |  | ||||||
| 	"syscall" |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"github.com/influxdb/telegraf/testutil" |  | ||||||
| 	"github.com/shirou/gopsutil/cpu" |  | ||||||
| 	"github.com/shirou/gopsutil/disk" |  | ||||||
| 	"github.com/shirou/gopsutil/mem" |  | ||||||
| 	"github.com/shirou/gopsutil/net" |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| 	"github.com/stretchr/testify/require" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestSystemStats_GenerateStats(t *testing.T) { |  | ||||||
| 	var mps MockPS |  | ||||||
| 
 |  | ||||||
| 	defer mps.AssertExpectations(t) |  | ||||||
| 
 |  | ||||||
| 	var acc testutil.Accumulator |  | ||||||
| 
 |  | ||||||
| 	cts := cpu.CPUTimesStat{ |  | ||||||
| 		CPU:       "cpu0", |  | ||||||
| 		User:      3.1, |  | ||||||
| 		System:    8.2, |  | ||||||
| 		Idle:      80.1, |  | ||||||
| 		Nice:      1.3, |  | ||||||
| 		Iowait:    0.2, |  | ||||||
| 		Irq:       0.1, |  | ||||||
| 		Softirq:   0.11, |  | ||||||
| 		Steal:     0.0511, |  | ||||||
| 		Guest:     8.1, |  | ||||||
| 		GuestNice: 0.324, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	cts2 := cpu.CPUTimesStat{ |  | ||||||
| 		CPU:       "cpu0", |  | ||||||
| 		User:      11.4,     // increased by 8.3
 |  | ||||||
| 		System:    10.9,     // increased by 2.7
 |  | ||||||
| 		Idle:      158.8699, // increased by 78.7699 (for total increase of 100)
 |  | ||||||
| 		Nice:      2.5,      // increased by 1.2
 |  | ||||||
| 		Iowait:    0.7,      // increased by 0.5
 |  | ||||||
| 		Irq:       1.2,      // increased by 1.1
 |  | ||||||
| 		Softirq:   0.31,     // increased by 0.2
 |  | ||||||
| 		Steal:     0.2812,   // increased by 0.0001
 |  | ||||||
| 		Guest:     12.9,     // increased by 4.8
 |  | ||||||
| 		GuestNice: 2.524,    // increased by 2.2
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil) |  | ||||||
| 
 |  | ||||||
| 	du := []*disk.DiskUsageStat{ |  | ||||||
| 		{ |  | ||||||
| 			Path:        "/", |  | ||||||
| 			Fstype:      "ext4", |  | ||||||
| 			Total:       128, |  | ||||||
| 			Free:        23, |  | ||||||
| 			InodesTotal: 1234, |  | ||||||
| 			InodesFree:  234, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Path:        "/home", |  | ||||||
| 			Fstype:      "ext4", |  | ||||||
| 			Total:       256, |  | ||||||
| 			Free:        46, |  | ||||||
| 			InodesTotal: 2468, |  | ||||||
| 			InodesFree:  468, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("DiskUsage").Return(du, nil) |  | ||||||
| 
 |  | ||||||
| 	diskio1 := disk.DiskIOCountersStat{ |  | ||||||
| 
 |  | ||||||
| 		ReadCount:    888, |  | ||||||
| 		WriteCount:   5341, |  | ||||||
| 		ReadBytes:    100000, |  | ||||||
| 		WriteBytes:   200000, |  | ||||||
| 		ReadTime:     7123, |  | ||||||
| 		WriteTime:    9087, |  | ||||||
| 		Name:         "sda1", |  | ||||||
| 		IoTime:       123552, |  | ||||||
| 		SerialNumber: "ab-123-ad", |  | ||||||
| 	} |  | ||||||
| 	diskio2 := disk.DiskIOCountersStat{ |  | ||||||
| 		ReadCount:    444, |  | ||||||
| 		WriteCount:   2341, |  | ||||||
| 		ReadBytes:    200000, |  | ||||||
| 		WriteBytes:   400000, |  | ||||||
| 		ReadTime:     3123, |  | ||||||
| 		WriteTime:    6087, |  | ||||||
| 		Name:         "sdb1", |  | ||||||
| 		IoTime:       246552, |  | ||||||
| 		SerialNumber: "bb-123-ad", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("DiskIO").Return(map[string]disk.DiskIOCountersStat{"sda1": diskio1, "sdb1": diskio2}, nil) |  | ||||||
| 
 |  | ||||||
| 	netio := net.NetIOCountersStat{ |  | ||||||
| 		Name:        "eth0", |  | ||||||
| 		BytesSent:   1123, |  | ||||||
| 		BytesRecv:   8734422, |  | ||||||
| 		PacketsSent: 781, |  | ||||||
| 		PacketsRecv: 23456, |  | ||||||
| 		Errin:       832, |  | ||||||
| 		Errout:      8, |  | ||||||
| 		Dropin:      7, |  | ||||||
| 		Dropout:     1, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("NetIO").Return([]net.NetIOCountersStat{netio}, nil) |  | ||||||
| 
 |  | ||||||
| 	netprotos := []net.NetProtoCountersStat{ |  | ||||||
| 		net.NetProtoCountersStat{ |  | ||||||
| 			Protocol: "Udp", |  | ||||||
| 			Stats: map[string]int64{ |  | ||||||
| 				"InDatagrams": 4655, |  | ||||||
| 				"NoPorts":     892592, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 	mps.On("NetProto").Return(netprotos, nil) |  | ||||||
| 
 |  | ||||||
| 	vms := &mem.VirtualMemoryStat{ |  | ||||||
| 		Total:     12400, |  | ||||||
| 		Available: 7600, |  | ||||||
| 		Used:      5000, |  | ||||||
| 		Free:      1235, |  | ||||||
| 		// Active:      8134,
 |  | ||||||
| 		// Inactive:    1124,
 |  | ||||||
| 		// Buffers:     771,
 |  | ||||||
| 		// Cached:      4312,
 |  | ||||||
| 		// Wired:       134,
 |  | ||||||
| 		// Shared:      2142,
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("VMStat").Return(vms, nil) |  | ||||||
| 
 |  | ||||||
| 	sms := &mem.SwapMemoryStat{ |  | ||||||
| 		Total:       8123, |  | ||||||
| 		Used:        1232, |  | ||||||
| 		Free:        6412, |  | ||||||
| 		UsedPercent: 12.2, |  | ||||||
| 		Sin:         7, |  | ||||||
| 		Sout:        830, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("SwapStat").Return(sms, nil) |  | ||||||
| 
 |  | ||||||
| 	netstats := []net.NetConnectionStat{ |  | ||||||
| 		net.NetConnectionStat{ |  | ||||||
| 			Type: syscall.SOCK_DGRAM, |  | ||||||
| 		}, |  | ||||||
| 		net.NetConnectionStat{ |  | ||||||
| 			Status: "ESTABLISHED", |  | ||||||
| 		}, |  | ||||||
| 		net.NetConnectionStat{ |  | ||||||
| 			Status: "ESTABLISHED", |  | ||||||
| 		}, |  | ||||||
| 		net.NetConnectionStat{ |  | ||||||
| 			Status: "CLOSE", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mps.On("NetConnections").Return(netstats, nil) |  | ||||||
| 
 |  | ||||||
| 	cs := NewCPUStats(&mps) |  | ||||||
| 
 |  | ||||||
| 	cputags := map[string]string{ |  | ||||||
| 		"cpu": "cpu0", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	preCPUPoints := len(acc.Points) |  | ||||||
| 	err := cs.Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 	numCPUPoints := len(acc.Points) - preCPUPoints |  | ||||||
| 
 |  | ||||||
| 	expectedCPUPoints := 10 |  | ||||||
| 	assert.Equal(t, expectedCPUPoints, numCPUPoints) |  | ||||||
| 
 |  | ||||||
| 	// Computed values are checked with delta > 0 becasue of floating point arithmatic
 |  | ||||||
| 	// imprecision
 |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_user", 3.1, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_system", 8.2, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_idle", 80.1, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_nice", 1.3, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_iowait", 0.2, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_irq", 0.1, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_softirq", 0.11, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_steal", 0.0511, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_guest", 8.1, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_guest_nice", 0.324, 0, cputags) |  | ||||||
| 
 |  | ||||||
| 	mps2 := MockPS{} |  | ||||||
| 	mps2.On("CPUTimes").Return([]cpu.CPUTimesStat{cts2}, nil) |  | ||||||
| 	cs.ps = &mps2 |  | ||||||
| 
 |  | ||||||
| 	// Should have added cpu percentages too
 |  | ||||||
| 	err = cs.Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	numCPUPoints = len(acc.Points) - (preCPUPoints + numCPUPoints) |  | ||||||
| 	expectedCPUPoints = 20 |  | ||||||
| 	assert.Equal(t, expectedCPUPoints, numCPUPoints) |  | ||||||
| 
 |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_user", 11.4, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_system", 10.9, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_idle", 158.8699, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_nice", 2.5, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_iowait", 0.7, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_irq", 1.2, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_softirq", 0.31, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_steal", 0.2812, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_guest", 12.9, 0, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "time_guest_nice", 2.524, 0, cputags) |  | ||||||
| 
 |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_user", 8.3, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_system", 2.7, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_idle", 78.7699, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_nice", 1.2, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_iowait", 0.5, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_irq", 1.1, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_softirq", 0.2, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_steal", 0.2301, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_guest", 4.8, 0.0005, cputags) |  | ||||||
| 	assertContainsTaggedFloat(t, &acc, "usage_guest_nice", 2.2, 0.0005, cputags) |  | ||||||
| 
 |  | ||||||
| 	preDiskPoints := len(acc.Points) |  | ||||||
| 
 |  | ||||||
| 	err = (&DiskStats{ps: &mps}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	numDiskPoints := len(acc.Points) - preDiskPoints |  | ||||||
| 	expectedAllDiskPoints := 12 |  | ||||||
| 	assert.Equal(t, expectedAllDiskPoints, numDiskPoints) |  | ||||||
| 
 |  | ||||||
| 	tags1 := map[string]string{ |  | ||||||
| 		"path":   "/", |  | ||||||
| 		"fstype": "ext4", |  | ||||||
| 	} |  | ||||||
| 	tags2 := map[string]string{ |  | ||||||
| 		"path":   "/home", |  | ||||||
| 		"fstype": "ext4", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("total", uint64(128), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("used", uint64(105), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("free", uint64(23), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_total", uint64(1234), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_free", uint64(234), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_used", uint64(1000), tags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("total", uint64(256), tags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("used", uint64(210), tags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("free", uint64(46), tags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_total", uint64(2468), tags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_free", uint64(468), tags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("inodes_used", uint64(2000), tags2)) |  | ||||||
| 
 |  | ||||||
| 	// We expect 6 more DiskPoints to show up with an explicit match on "/"
 |  | ||||||
| 	// and /home not matching the /dev in Mountpoints
 |  | ||||||
| 	err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/dev"}}).Gather(&acc) |  | ||||||
| 	assert.Equal(t, preDiskPoints+expectedAllDiskPoints+6, len(acc.Points)) |  | ||||||
| 
 |  | ||||||
| 	// We should see all the diskpoints as Mountpoints includes both
 |  | ||||||
| 	// / and /home
 |  | ||||||
| 	err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/home"}}).Gather(&acc) |  | ||||||
| 	assert.Equal(t, preDiskPoints+2*expectedAllDiskPoints+6, len(acc.Points)) |  | ||||||
| 
 |  | ||||||
| 	err = (&NetIOStats{ps: &mps, skipChecks: true}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	ntags := map[string]string{ |  | ||||||
| 		"interface": "eth0", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("bytes_sent", uint64(1123), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("bytes_recv", uint64(8734422), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("packets_sent", uint64(781), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("packets_recv", uint64(23456), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("err_in", uint64(832), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("err_out", uint64(8), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("drop_in", uint64(7), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("drop_out", uint64(1), ntags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateValue("udp_noports", int64(892592))) |  | ||||||
| 	assert.NoError(t, acc.ValidateValue("udp_indatagrams", int64(4655))) |  | ||||||
| 
 |  | ||||||
| 	preDiskIOPoints := len(acc.Points) |  | ||||||
| 
 |  | ||||||
| 	err = (&DiskIOStats{ps: &mps}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	numDiskIOPoints := len(acc.Points) - preDiskIOPoints |  | ||||||
| 	expectedAllDiskIOPoints := 14 |  | ||||||
| 	assert.Equal(t, expectedAllDiskIOPoints, numDiskIOPoints) |  | ||||||
| 
 |  | ||||||
| 	dtags1 := map[string]string{ |  | ||||||
| 		"name":   "sda1", |  | ||||||
| 		"serial": "ab-123-ad", |  | ||||||
| 	} |  | ||||||
| 	dtags2 := map[string]string{ |  | ||||||
| 		"name":   "sdb1", |  | ||||||
| 		"serial": "bb-123-ad", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("reads", uint64(888), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("writes", uint64(5341), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(100000), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(200000), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(7123), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(9087), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(123552), dtags1)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags2)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags2)) |  | ||||||
| 
 |  | ||||||
| 	// We expect 7 more DiskIOPoints to show up with an explicit match on "sdb1"
 |  | ||||||
| 	// and serial should be missing from the tags with SkipSerialNumber set
 |  | ||||||
| 	err = (&DiskIOStats{ps: &mps, Devices: []string{"sdb1"}, SkipSerialNumber: true}).Gather(&acc) |  | ||||||
| 	assert.Equal(t, preDiskIOPoints+expectedAllDiskIOPoints+7, len(acc.Points)) |  | ||||||
| 
 |  | ||||||
| 	dtags3 := map[string]string{ |  | ||||||
| 		"name": "sdb1", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags3)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags3)) |  | ||||||
| 
 |  | ||||||
| 	err = (&MemStats{&mps}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	vmtags := map[string]string(nil) |  | ||||||
| 
 |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("total", uint64(12400), vmtags)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("available", uint64(7600), vmtags)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("used", uint64(5000), vmtags)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("available_percent", |  | ||||||
| 		float64(7600)/float64(12400)*100, |  | ||||||
| 		vmtags)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("used_percent", |  | ||||||
| 		float64(5000)/float64(12400)*100, |  | ||||||
| 		vmtags)) |  | ||||||
| 	assert.True(t, acc.CheckTaggedValue("free", uint64(1235), vmtags)) |  | ||||||
| 
 |  | ||||||
| 	acc.Points = nil |  | ||||||
| 
 |  | ||||||
| 	err = (&SwapStats{&mps}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	swaptags := map[string]string(nil) |  | ||||||
| 
 |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("total", uint64(8123), swaptags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("used", uint64(1232), swaptags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("used_percent", float64(12.2), swaptags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("free", uint64(6412), swaptags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("in", uint64(7), swaptags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("out", uint64(830), swaptags)) |  | ||||||
| 
 |  | ||||||
| 	acc.Points = nil |  | ||||||
| 
 |  | ||||||
| 	err = (&NetStats{&mps}).Gather(&acc) |  | ||||||
| 	require.NoError(t, err) |  | ||||||
| 	netstattags := map[string]string(nil) |  | ||||||
| 
 |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("tcp_established", 2, netstattags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("tcp_close", 1, netstattags)) |  | ||||||
| 	assert.NoError(t, acc.ValidateTaggedValue("udp_socket", 1, netstattags)) |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Asserts that a given accumulator contains a measurment of type float64 with
 |  | ||||||
| // specific tags within a certain distance of a given expected value. Asserts a failure
 |  | ||||||
| // if the measurement is of the wrong type, or if no matching measurements are found
 |  | ||||||
| //
 |  | ||||||
| // Paramaters:
 |  | ||||||
| //     t *testing.T            : Testing object to use
 |  | ||||||
| //     acc testutil.Accumulator: Accumulator to examine
 |  | ||||||
| //     measurement string      : Name of the measurement to examine
 |  | ||||||
| //     expectedValue float64   : Value to search for within the measurement
 |  | ||||||
| //     delta float64           : Maximum acceptable distance of an accumulated value
 |  | ||||||
| //                               from the expectedValue parameter. Useful when
 |  | ||||||
| //                               floating-point arithmatic imprecision makes looking
 |  | ||||||
| //                               for an exact match impractical
 |  | ||||||
| //     tags map[string]string  : Tag set the found measurement must have. Set to nil to
 |  | ||||||
| //                               ignore the tag set.
 |  | ||||||
| func assertContainsTaggedFloat( |  | ||||||
| 	t *testing.T, |  | ||||||
| 	acc *testutil.Accumulator, |  | ||||||
| 	measurement string, |  | ||||||
| 	expectedValue float64, |  | ||||||
| 	delta float64, |  | ||||||
| 	tags map[string]string, |  | ||||||
| ) { |  | ||||||
| 	var actualValue float64 |  | ||||||
| 	for _, pt := range acc.Points { |  | ||||||
| 		if pt.Measurement == measurement { |  | ||||||
| 			if (tags == nil) || reflect.DeepEqual(pt.Tags, tags) { |  | ||||||
| 				if value, ok := pt.Fields["value"].(float64); ok { |  | ||||||
| 					actualValue = value |  | ||||||
| 					if (value >= expectedValue-delta) && (value <= expectedValue+delta) { |  | ||||||
| 						// Found the point, return without failing
 |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 				} else { |  | ||||||
| 					assert.Fail(t, fmt.Sprintf("Measurement \"%s\" does not have type float64", |  | ||||||
| 						measurement)) |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	msg := fmt.Sprintf("Could not find measurement \"%s\" with requested tags within %f of %f, Actual: %f", |  | ||||||
| 		measurement, delta, expectedValue, actualValue) |  | ||||||
| 	assert.Fail(t, msg) |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue