Moved system package inputs out to top level (#4406)
This commit is contained in:
committed by
Daniel Nelson
parent
9a14d1f074
commit
7b73b0db3a
@@ -1,99 +0,0 @@
|
||||
# Telegraf plugin: CPU
|
||||
|
||||
#### Plugin arguments:
|
||||
- **totalcpu** boolean: If true, include `cpu-total` data
|
||||
- **percpu** boolean: If true, include data on a per-cpu basis `cpu0, cpu1, etc.`
|
||||
|
||||
|
||||
##### Configuration:
|
||||
```
|
||||
[[inputs.cpu]]
|
||||
## Whether to report per-cpu stats or not
|
||||
percpu = true
|
||||
## Whether to report total system cpu stats or not
|
||||
totalcpu = true
|
||||
## If true, collect raw CPU time metrics.
|
||||
collect_cpu_time = false
|
||||
## If true, compute and report the sum of all non-idle CPU states.
|
||||
report_active = false
|
||||
```
|
||||
|
||||
#### Description
|
||||
|
||||
The CPU plugin collects standard CPU metrics as defined in `man proc`. All
|
||||
architectures do not support all of these metrics.
|
||||
|
||||
```
|
||||
cpu 3357 0 4313 1362393
|
||||
The amount of time, measured in units of USER_HZ (1/100ths of a second on
|
||||
most architectures, use sysconf(_SC_CLK_TCK) to obtain the right value),
|
||||
that the system spent in various states:
|
||||
|
||||
user (1) Time spent in user mode.
|
||||
|
||||
nice (2) Time spent in user mode with low priority (nice).
|
||||
|
||||
system (3) Time spent in system mode.
|
||||
|
||||
idle (4) Time spent in the idle task. This value should be USER_HZ times
|
||||
the second entry in the /proc/uptime pseudo-file.
|
||||
|
||||
iowait (since Linux 2.5.41)
|
||||
(5) Time waiting for I/O to complete.
|
||||
|
||||
irq (since Linux 2.6.0-test4)
|
||||
(6) Time servicing interrupts.
|
||||
|
||||
softirq (since Linux 2.6.0-test4)
|
||||
(7) Time servicing softirqs.
|
||||
|
||||
steal (since Linux 2.6.11)
|
||||
(8) Stolen time, which is the time spent in other operating systems
|
||||
when running in a virtualized environment
|
||||
|
||||
guest (since Linux 2.6.24)
|
||||
(9) Time spent running a virtual CPU for guest operating systems
|
||||
under the control of the Linux kernel.
|
||||
|
||||
guest_nice (since Linux 2.6.33)
|
||||
(10) Time spent running a niced guest (virtual CPU for guest operating systems under the control of the Linux kernel).
|
||||
```
|
||||
|
||||
# Measurements:
|
||||
### CPU Time measurements:
|
||||
|
||||
Meta:
|
||||
- units: CPU Time
|
||||
- tags: `cpu=<cpuN> or <cpu-total>`
|
||||
|
||||
Measurement names:
|
||||
- cpu_time_user
|
||||
- cpu_time_system
|
||||
- cpu_time_idle
|
||||
- cpu_time_active (must be explicitly enabled by setting `report_active = true`)
|
||||
- cpu_time_nice
|
||||
- cpu_time_iowait
|
||||
- cpu_time_irq
|
||||
- cpu_time_softirq
|
||||
- cpu_time_steal
|
||||
- cpu_time_guest
|
||||
- cpu_time_guest_nice
|
||||
|
||||
### CPU Usage Percent Measurements:
|
||||
|
||||
Meta:
|
||||
- units: percent (out of 100)
|
||||
- tags: `cpu=<cpuN> or <cpu-total>`
|
||||
|
||||
Measurement names:
|
||||
- cpu_usage_user
|
||||
- cpu_usage_system
|
||||
- cpu_usage_idle
|
||||
- cpu_usage_active (must be explicitly enabled by setting `report_active = true`)
|
||||
- cpu_usage_nice
|
||||
- cpu_usage_iowait
|
||||
- cpu_usage_irq
|
||||
- cpu_usage_softirq
|
||||
- cpu_usage_steal
|
||||
- cpu_usage_guest
|
||||
- cpu_usage_guest_nice
|
||||
@@ -1,129 +0,0 @@
|
||||
# DiskIO Input Plugin
|
||||
|
||||
The diskio input plugin gathers metrics about disk traffic and timing.
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Read metrics about disk IO by device
|
||||
[[inputs.diskio]]
|
||||
## By default, telegraf will gather stats for all devices including
|
||||
## disk partitions.
|
||||
## Setting devices will restrict the stats to the specified devices.
|
||||
# devices = ["sda", "sdb"]
|
||||
## Uncomment the following line if you need disk serial numbers.
|
||||
# skip_serial_number = false
|
||||
#
|
||||
## On systems which support it, device metadata can be added in the form of
|
||||
## tags.
|
||||
## Currently only Linux is supported via udev properties. You can view
|
||||
## available properties for a device by running:
|
||||
## 'udevadm info -q property -n /dev/sda'
|
||||
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
||||
#
|
||||
## Using the same metadata source as device_tags, you can also customize the
|
||||
## name of the device via templates.
|
||||
## The 'name_templates' parameter is a list of templates to try and apply to
|
||||
## the device. The template may contain variables in the form of '$PROPERTY' or
|
||||
## '${PROPERTY}'. The first template which does not contain any variables not
|
||||
## present for the device is used as the device name tag.
|
||||
## The typical use case is for LVM volumes, to get the VG/LV name instead of
|
||||
## the near-meaningless DM-0 name.
|
||||
# name_templates = ["$ID_FS_LABEL","$DM_VG_NAME/$DM_LV_NAME"]
|
||||
```
|
||||
|
||||
#### Docker container
|
||||
|
||||
To monitor the Docker engine host from within a container you will need to
|
||||
mount the host's filesystem into the container and set the `HOST_PROC`
|
||||
environment variable to the location of the `/proc` filesystem. Additionally,
|
||||
it is required to use privileged mode to provide access to `/dev`.
|
||||
|
||||
If you are using the `device_tags` or `name_templates` options, you will need
|
||||
to bind mount `/run/udev` into the container.
|
||||
|
||||
```
|
||||
docker run --privileged -v /:/hostfs:ro -v /run/udev:/run/udev:ro -e HOST_PROC=/hostfs/proc telegraf
|
||||
```
|
||||
|
||||
### Metrics:
|
||||
|
||||
- diskio
|
||||
- tags:
|
||||
- name (device name)
|
||||
- serial (device serial number)
|
||||
- fields:
|
||||
- reads (integer, counter)
|
||||
- writes (integer, counter)
|
||||
- read_bytes (integer, counter, bytes)
|
||||
- write_bytes (integer, counter, bytes)
|
||||
- read_time (integer, counter, milliseconds)
|
||||
- write_time (integer, counter, milliseconds)
|
||||
- io_time (integer, counter, milliseconds)
|
||||
- weighted_io_time (integer, counter, milliseconds)
|
||||
- iops_in_progress (integer, gauge)
|
||||
|
||||
On linux these values correspond to the values in
|
||||
[`/proc/diskstats`](https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats)
|
||||
and
|
||||
[`/sys/block/<dev>/stat`](https://www.kernel.org/doc/Documentation/block/stat.txt).
|
||||
|
||||
#### `reads` & `writes`:
|
||||
|
||||
These values increment when an I/O request completes.
|
||||
|
||||
#### `read_bytes` & `write_bytes`:
|
||||
|
||||
These values count the number of bytes read from or written to this
|
||||
block device.
|
||||
|
||||
#### `read_time` & `write_time`:
|
||||
|
||||
These values count the number of milliseconds that I/O requests have
|
||||
waited on this block device. If there are multiple I/O requests waiting,
|
||||
these values will increase at a rate greater than 1000/second; for
|
||||
example, if 60 read requests wait for an average of 30 ms, the read_time
|
||||
field will increase by 60*30 = 1800.
|
||||
|
||||
#### `io_time`:
|
||||
|
||||
This value counts the number of milliseconds during which the device has
|
||||
had I/O requests queued.
|
||||
|
||||
#### `weighted_io_time`:
|
||||
|
||||
This value counts the number of milliseconds that I/O requests have waited
|
||||
on this block device. If there are multiple I/O requests waiting, this
|
||||
value will increase as the product of the number of milliseconds times the
|
||||
number of requests waiting (see `read_time` above for an example).
|
||||
|
||||
#### `iops_in_progress`:
|
||||
|
||||
This value counts the number of I/O requests that have been issued to
|
||||
the device driver but have not yet completed. It does not include I/O
|
||||
requests that are in the queue but not yet issued to the device driver.
|
||||
|
||||
### Sample Queries:
|
||||
|
||||
#### Calculate percent IO utilization per disk and host:
|
||||
```
|
||||
SELECT non_negative_derivative(last("io_time"),1ms) FROM "diskio" WHERE time > now() - 30m GROUP BY "host","name",time(60s)
|
||||
```
|
||||
|
||||
#### Calculate average queue depth:
|
||||
`iops_in_progress` will give you an instantaneous value. This will give you the average between polling intervals.
|
||||
```
|
||||
SELECT non_negative_derivative(last("weighted_io_time",1ms)) from "diskio" WHERE time > now() - 30m GROUP BY "host","name",time(60s)
|
||||
```
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
diskio,name=sda weighted_io_time=8411917i,read_time=7446444i,write_time=971489i,io_time=866197i,write_bytes=5397686272i,iops_in_progress=0i,reads=2970519i,writes=361139i,read_bytes=119528903168i 1502467254359000000
|
||||
diskio,name=sda1 reads=2149i,read_bytes=10753536i,write_bytes=20697088i,write_time=346i,weighted_io_time=505i,writes=2110i,read_time=161i,io_time=208i,iops_in_progress=0i 1502467254359000000
|
||||
diskio,name=sda2 reads=2968279i,writes=359029i,write_bytes=5376989184i,iops_in_progress=0i,weighted_io_time=8411250i,read_bytes=119517334528i,read_time=7446249i,write_time=971143i,io_time=866010i 1502467254359000000
|
||||
diskio,name=sdb writes=99391856i,write_time=466700894i,io_time=630259874i,weighted_io_time=4245949844i,reads=2750773828i,read_bytes=80667939499008i,write_bytes=6329347096576i,read_time=3783042534i,iops_in_progress=2i 1502467254359000000
|
||||
diskio,name=centos/root read_time=7472461i,write_time=950014i,iops_in_progress=0i,weighted_io_time=8424447i,writes=298543i,read_bytes=119510105088i,io_time=837421i,reads=2971769i,write_bytes=5192795648i 1502467254359000000
|
||||
diskio,name=centos/var_log reads=1065i,writes=69711i,read_time=1083i,write_time=35376i,read_bytes=6828032i,write_bytes=184193536i,io_time=29699i,iops_in_progress=0i,weighted_io_time=36460i 1502467254359000000
|
||||
diskio,name=postgresql/pgsql write_time=478267417i,io_time=631098730i,iops_in_progress=2i,weighted_io_time=4263637564i,reads=2750777151i,writes=110044361i,read_bytes=80667939288064i,write_bytes=6329347096576i,read_time=3784499336i 1502467254359000000
|
||||
```
|
||||
@@ -1,61 +0,0 @@
|
||||
# Disk Input Plugin
|
||||
|
||||
The disk input plugin gathers metrics about disk usage.
|
||||
|
||||
Note that `used_percent` is calculated by doing `used / (used + free)`, _not_
|
||||
`used / total`, which is how the unix `df` command does it. See
|
||||
https://en.wikipedia.org/wiki/Df_(Unix) for more details.
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Read metrics about disk usage by mount point
|
||||
[[inputs.disk]]
|
||||
## By default stats will be gathered for all mount points.
|
||||
## Set mount_points will restrict the stats to only the specified mount points.
|
||||
# mount_points = ["/"]
|
||||
|
||||
## Ignore mount points by filesystem type.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "overlay", "aufs", "squashfs"]
|
||||
```
|
||||
|
||||
#### Docker container
|
||||
|
||||
To monitor the Docker engine host from within a container you will need to
|
||||
mount the host's filesystem into the container and set the `HOST_PROC`
|
||||
environment variable to the location of the `/proc` filesystem. If desired, you can
|
||||
also set the `HOST_MOUNT_PREFIX` environment variable to the prefix containing
|
||||
the `/proc` directory, when present this variable is stripped from the
|
||||
reported `path` tag.
|
||||
|
||||
```
|
||||
docker run -v /:/hostfs:ro -e HOST_MOUNT_PREFIX=/hostfs -e HOST_PROC=/hostfs/proc telegraf
|
||||
```
|
||||
|
||||
### Metrics:
|
||||
|
||||
- disk
|
||||
- tags:
|
||||
- fstype (filesystem type)
|
||||
- device (device file)
|
||||
- path (mount point path)
|
||||
- mode (whether the mount is rw or ro)
|
||||
- fields:
|
||||
- free (integer, bytes)
|
||||
- total (integer, bytes)
|
||||
- used (integer, bytes)
|
||||
- used_percent (float, percent)
|
||||
- inodes_free (integer, files)
|
||||
- inodes_total (integer, files)
|
||||
- inodes_used (integer, files)
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
disk,fstype=hfs,mode=ro,path=/ free=398407520256i,inodes_free=97267461i,inodes_total=121847806i,inodes_used=24580345i,total=499088621568i,used=100418957312i,used_percent=20.131039916242397 1453832006274071563
|
||||
disk,fstype=devfs,mode=rw,path=/dev free=0i,inodes_free=0i,inodes_total=628i,inodes_used=628i,total=185856i,used=185856i,used_percent=100 1453832006274137913
|
||||
disk,fstype=autofs,mode=rw,path=/net free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0 1453832006274157077
|
||||
disk,fstype=autofs,mode=rw,path=/home free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0 1453832006274169688
|
||||
```
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# Kernel Input Plugin
|
||||
|
||||
This plugin is only available on Linux.
|
||||
|
||||
The kernel plugin gathers info about the kernel that doesn't fit into other
|
||||
plugins. In general, it is the statistics available in `/proc/stat` that are
|
||||
not covered by other plugins as well as the value of `/proc/sys/kernel/random/entropy_avail`
|
||||
|
||||
The metrics are documented in `man proc` under the `/proc/stat` section.
|
||||
The metrics are documented in `man 4 random` under the `/proc/stat` section.
|
||||
|
||||
```
|
||||
|
||||
|
||||
/proc/sys/kernel/random/entropy_avail
|
||||
Contains the value of available entropy
|
||||
|
||||
/proc/stat
|
||||
kernel/system statistics. Varies with architecture. Common entries include:
|
||||
|
||||
page 5741 1808
|
||||
The number of pages the system paged in and the number that were paged out (from disk).
|
||||
|
||||
swap 1 0
|
||||
The number of swap pages that have been brought in and out.
|
||||
|
||||
intr 1462898
|
||||
This line shows counts of interrupts serviced since boot time, for each of
|
||||
the possible system interrupts. The first column is the total of all
|
||||
interrupts serviced; each subsequent column is the total for a particular interrupt.
|
||||
|
||||
ctxt 115315
|
||||
The number of context switches that the system underwent.
|
||||
|
||||
btime 769041601
|
||||
boot time, in seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
|
||||
|
||||
processes 86031
|
||||
Number of forks since boot.
|
||||
```
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Get kernel statistics from /proc/stat
|
||||
[[inputs.kernel]]
|
||||
# no configuration
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- kernel
|
||||
- boot_time (integer, seconds since epoch, `btime`)
|
||||
- context_switches (integer, `ctxt`)
|
||||
- disk_pages_in (integer, `page (0)`)
|
||||
- disk_pages_out (integer, `page (1)`)
|
||||
- interrupts (integer, `intr`)
|
||||
- processes_forked (integer, `processes`)
|
||||
- entropy_avail (integer, `entropy_available`)
|
||||
|
||||
### Tags:
|
||||
|
||||
None
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
$ telegraf --config ~/ws/telegraf.conf --input-filter kernel --test
|
||||
* Plugin: kernel, Collection 1
|
||||
> kernel entropy_available=2469i,boot_time=1457505775i,context_switches=2626618i,disk_pages_in=5741i,disk_pages_out=1808i,interrupts=1472736i,processes_forked=10673i 1457613402960879816
|
||||
```
|
||||
@@ -1,225 +0,0 @@
|
||||
# Kernel VMStat Input Plugin
|
||||
|
||||
The kernel_vmstat plugin gathers virtual memory statistics
|
||||
by reading /proc/vmstat. For a full list of available fields see the
|
||||
/proc/vmstat section of the [proc man page](http://man7.org/linux/man-pages/man5/proc.5.html).
|
||||
For a better idea of what each field represents, see the
|
||||
[vmstat man page](http://linux.die.net/man/8/vmstat).
|
||||
|
||||
|
||||
```
|
||||
/proc/vmstat
|
||||
kernel/system statistics. Common entries include (from http://www.linuxinsight.com/proc_vmstat.html):
|
||||
|
||||
Number of pages that are dirty, under writeback or unstable:
|
||||
|
||||
nr_dirty 1550
|
||||
nr_writeback 0
|
||||
nr_unstable 0
|
||||
|
||||
Number of pages allocated to page tables, mapped by files or allocated by the kernel slab allocator:
|
||||
|
||||
nr_page_table_pages 699
|
||||
nr_mapped 139596
|
||||
nr_slab 42723
|
||||
|
||||
Number of pageins and pageouts (since the last boot):
|
||||
|
||||
pgpgin 33754195
|
||||
pgpgout 38985992
|
||||
|
||||
Number of swapins and swapouts (since the last boot):
|
||||
|
||||
pswpin 2473
|
||||
pswpout 2995
|
||||
|
||||
Number of page allocations per zone (since the last boot):
|
||||
|
||||
pgalloc_high 0
|
||||
pgalloc_normal 110123213
|
||||
pgalloc_dma32 0
|
||||
pgalloc_dma 415219
|
||||
|
||||
Number of page frees, activations and deactivations (since the last boot):
|
||||
|
||||
pgfree 110549163
|
||||
pgactivate 4509729
|
||||
pgdeactivate 2136215
|
||||
|
||||
Number of minor and major page faults (since the last boot):
|
||||
|
||||
pgfault 80663722
|
||||
pgmajfault 49813
|
||||
|
||||
Number of page refills (per zone, since the last boot):
|
||||
|
||||
pgrefill_high 0
|
||||
pgrefill_normal 5817500
|
||||
pgrefill_dma32 0
|
||||
pgrefill_dma 149176
|
||||
|
||||
Number of page steals (per zone, since the last boot):
|
||||
|
||||
pgsteal_high 0
|
||||
pgsteal_normal 10421346
|
||||
pgsteal_dma32 0
|
||||
pgsteal_dma 142196
|
||||
|
||||
Number of pages scanned by the kswapd daemon (per zone, since the last boot):
|
||||
|
||||
pgscan_kswapd_high 0
|
||||
pgscan_kswapd_normal 10491424
|
||||
pgscan_kswapd_dma32 0
|
||||
pgscan_kswapd_dma 156130
|
||||
|
||||
Number of pages reclaimed directly (per zone, since the last boot):
|
||||
|
||||
pgscan_direct_high 0
|
||||
pgscan_direct_normal 11904
|
||||
pgscan_direct_dma32 0
|
||||
pgscan_direct_dma 225
|
||||
|
||||
Number of pages reclaimed via inode freeing (since the last boot):
|
||||
|
||||
pginodesteal 11
|
||||
|
||||
Number of slab objects scanned (since the last boot):
|
||||
|
||||
slabs_scanned 8926976
|
||||
|
||||
Number of pages reclaimed by kswapd (since the last boot):
|
||||
|
||||
kswapd_steal 10551674
|
||||
|
||||
Number of pages reclaimed by kswapd via inode freeing (since the last boot):
|
||||
|
||||
kswapd_inodesteal 338730
|
||||
|
||||
Number of kswapd's calls to page reclaim (since the last boot):
|
||||
|
||||
pageoutrun 181908
|
||||
|
||||
Number of direct reclaim calls (since the last boot):
|
||||
|
||||
allocstall 160
|
||||
|
||||
Miscellaneous statistics:
|
||||
|
||||
pgrotated 3781
|
||||
nr_bounce 0
|
||||
```
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Get kernel statistics from /proc/vmstat
|
||||
[[inputs.kernel_vmstat]]
|
||||
# no configuration
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- kernel_vmstat
|
||||
- nr_free_pages (integer, `nr_free_pages`)
|
||||
- nr_inactive_anon (integer, `nr_inactive_anon`)
|
||||
- nr_active_anon (integer, `nr_active_anon`)
|
||||
- nr_inactive_file (integer, `nr_inactive_file`)
|
||||
- nr_active_file (integer, `nr_active_file`)
|
||||
- nr_unevictable (integer, `nr_unevictable`)
|
||||
- nr_mlock (integer, `nr_mlock`)
|
||||
- nr_anon_pages (integer, `nr_anon_pages`)
|
||||
- nr_mapped (integer, `nr_mapped`)
|
||||
- nr_file_pages (integer, `nr_file_pages`)
|
||||
- nr_dirty (integer, `nr_dirty`)
|
||||
- nr_writeback (integer, `nr_writeback`)
|
||||
- nr_slab_reclaimable (integer, `nr_slab_reclaimable`)
|
||||
- nr_slab_unreclaimable (integer, `nr_slab_unreclaimable`)
|
||||
- nr_page_table_pages (integer, `nr_page_table_pages`)
|
||||
- nr_kernel_stack (integer, `nr_kernel_stack`)
|
||||
- nr_unstable (integer, `nr_unstable`)
|
||||
- nr_bounce (integer, `nr_bounce`)
|
||||
- nr_vmscan_write (integer, `nr_vmscan_write`)
|
||||
- nr_writeback_temp (integer, `nr_writeback_temp`)
|
||||
- nr_isolated_anon (integer, `nr_isolated_anon`)
|
||||
- nr_isolated_file (integer, `nr_isolated_file`)
|
||||
- nr_shmem (integer, `nr_shmem`)
|
||||
- numa_hit (integer, `numa_hit`)
|
||||
- numa_miss (integer, `numa_miss`)
|
||||
- numa_foreign (integer, `numa_foreign`)
|
||||
- numa_interleave (integer, `numa_interleave`)
|
||||
- numa_local (integer, `numa_local`)
|
||||
- numa_other (integer, `numa_other`)
|
||||
- nr_anon_transparent_hugepages (integer, `nr_anon_transparent_hugepages`)
|
||||
- pgpgin (integer, `pgpgin`)
|
||||
- pgpgout (integer, `pgpgout`)
|
||||
- pswpin (integer, `pswpin`)
|
||||
- pswpout (integer, `pswpout`)
|
||||
- pgalloc_dma (integer, `pgalloc_dma`)
|
||||
- pgalloc_dma32 (integer, `pgalloc_dma32`)
|
||||
- pgalloc_normal (integer, `pgalloc_normal`)
|
||||
- pgalloc_movable (integer, `pgalloc_movable`)
|
||||
- pgfree (integer, `pgfree`)
|
||||
- pgactivate (integer, `pgactivate`)
|
||||
- pgdeactivate (integer, `pgdeactivate`)
|
||||
- pgfault (integer, `pgfault`)
|
||||
- pgmajfault (integer, `pgmajfault`)
|
||||
- pgrefill_dma (integer, `pgrefill_dma`)
|
||||
- pgrefill_dma32 (integer, `pgrefill_dma32`)
|
||||
- pgrefill_normal (integer, `pgrefill_normal`)
|
||||
- pgrefill_movable (integer, `pgrefill_movable`)
|
||||
- pgsteal_dma (integer, `pgsteal_dma`)
|
||||
- pgsteal_dma32 (integer, `pgsteal_dma32`)
|
||||
- pgsteal_normal (integer, `pgsteal_normal`)
|
||||
- pgsteal_movable (integer, `pgsteal_movable`)
|
||||
- pgscan_kswapd_dma (integer, `pgscan_kswapd_dma`)
|
||||
- pgscan_kswapd_dma32 (integer, `pgscan_kswapd_dma32`)
|
||||
- pgscan_kswapd_normal (integer, `pgscan_kswapd_normal`)
|
||||
- pgscan_kswapd_movable (integer, `pgscan_kswapd_movable`)
|
||||
- pgscan_direct_dma (integer, `pgscan_direct_dma`)
|
||||
- pgscan_direct_dma32 (integer, `pgscan_direct_dma32`)
|
||||
- pgscan_direct_normal (integer, `pgscan_direct_normal`)
|
||||
- pgscan_direct_movable (integer, `pgscan_direct_movable`)
|
||||
- zone_reclaim_failed (integer, `zone_reclaim_failed`)
|
||||
- pginodesteal (integer, `pginodesteal`)
|
||||
- slabs_scanned (integer, `slabs_scanned`)
|
||||
- kswapd_steal (integer, `kswapd_steal`)
|
||||
- kswapd_inodesteal (integer, `kswapd_inodesteal`)
|
||||
- kswapd_low_wmark_hit_quickly (integer, `kswapd_low_wmark_hit_quickly`)
|
||||
- kswapd_high_wmark_hit_quickly (integer, `kswapd_high_wmark_hit_quickly`)
|
||||
- kswapd_skip_congestion_wait (integer, `kswapd_skip_congestion_wait`)
|
||||
- pageoutrun (integer, `pageoutrun`)
|
||||
- allocstall (integer, `allocstall`)
|
||||
- pgrotated (integer, `pgrotated`)
|
||||
- compact_blocks_moved (integer, `compact_blocks_moved`)
|
||||
- compact_pages_moved (integer, `compact_pages_moved`)
|
||||
- compact_pagemigrate_failed (integer, `compact_pagemigrate_failed`)
|
||||
- compact_stall (integer, `compact_stall`)
|
||||
- compact_fail (integer, `compact_fail`)
|
||||
- compact_success (integer, `compact_success`)
|
||||
- htlb_buddy_alloc_success (integer, `htlb_buddy_alloc_success`)
|
||||
- htlb_buddy_alloc_fail (integer, `htlb_buddy_alloc_fail`)
|
||||
- unevictable_pgs_culled (integer, `unevictable_pgs_culled`)
|
||||
- unevictable_pgs_scanned (integer, `unevictable_pgs_scanned`)
|
||||
- unevictable_pgs_rescued (integer, `unevictable_pgs_rescued`)
|
||||
- unevictable_pgs_mlocked (integer, `unevictable_pgs_mlocked`)
|
||||
- unevictable_pgs_munlocked (integer, `unevictable_pgs_munlocked`)
|
||||
- unevictable_pgs_cleared (integer, `unevictable_pgs_cleared`)
|
||||
- unevictable_pgs_stranded (integer, `unevictable_pgs_stranded`)
|
||||
- unevictable_pgs_mlockfreed (integer, `unevictable_pgs_mlockfreed`)
|
||||
- thp_fault_alloc (integer, `thp_fault_alloc`)
|
||||
- thp_fault_fallback (integer, `thp_fault_fallback`)
|
||||
- thp_collapse_alloc (integer, `thp_collapse_alloc`)
|
||||
- thp_collapse_alloc_failed (integer, `thp_collapse_alloc_failed`)
|
||||
- thp_split (integer, `thp_split`)
|
||||
|
||||
### Tags:
|
||||
|
||||
None
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
$ telegraf --config ~/ws/telegraf.conf --input-filter kernel_vmstat --test
|
||||
* Plugin: kernel_vmstat, Collection 1
|
||||
> kernel_vmstat allocstall=81496i,compact_blocks_moved=238196i,compact_fail=135220i,compact_pagemigrate_failed=0i,compact_pages_moved=6370588i,compact_stall=142092i,compact_success=6872i,htlb_buddy_alloc_fail=0i,htlb_buddy_alloc_success=0i,kswapd_high_wmark_hit_quickly=25439i,kswapd_inodesteal=29770874i,kswapd_low_wmark_hit_quickly=8756i,kswapd_skip_congestion_wait=0i,kswapd_steal=291534428i,nr_active_anon=2515657i,nr_active_file=2244914i,nr_anon_pages=1358675i,nr_anon_transparent_hugepages=2034i,nr_bounce=0i,nr_dirty=5690i,nr_file_pages=5153546i,nr_free_pages=78730i,nr_inactive_anon=426259i,nr_inactive_file=2366791i,nr_isolated_anon=0i,nr_isolated_file=0i,nr_kernel_stack=579i,nr_mapped=558821i,nr_mlock=0i,nr_page_table_pages=11115i,nr_shmem=541689i,nr_slab_reclaimable=459806i,nr_slab_unreclaimable=47859i,nr_unevictable=0i,nr_unstable=0i,nr_vmscan_write=6206i,nr_writeback=0i,nr_writeback_temp=0i,numa_foreign=0i,numa_hit=5113399878i,numa_interleave=35793i,numa_local=5113399878i,numa_miss=0i,numa_other=0i,pageoutrun=505006i,pgactivate=375664931i,pgalloc_dma=0i,pgalloc_dma32=122480220i,pgalloc_movable=0i,pgalloc_normal=5233176719i,pgdeactivate=122735906i,pgfault=8699921410i,pgfree=5359765021i,pginodesteal=9188431i,pgmajfault=122210i,pgpgin=219717626i,pgpgout=3495885510i,pgrefill_dma=0i,pgrefill_dma32=1180010i,pgrefill_movable=0i,pgrefill_normal=119866676i,pgrotated=60620i,pgscan_direct_dma=0i,pgscan_direct_dma32=12256i,pgscan_direct_movable=0i,pgscan_direct_normal=31501600i,pgscan_kswapd_dma=0i,pgscan_kswapd_dma32=4480608i,pgscan_kswapd_movable=0i,pgscan_kswapd_normal=287857984i,pgsteal_dma=0i,pgsteal_dma32=4466436i,pgsteal_movable=0i,pgsteal_normal=318463755i,pswpin=2092i,pswpout=6206i,slabs_scanned=93775616i,thp_collapse_alloc=24857i,thp_collapse_alloc_failed=102214i,thp_fault_alloc=346219i,thp_fault_fallback=895453i,thp_split=9817i,unevictable_pgs_cleared=0i,unevictable_pgs_culled=1531i,unevictable_pgs_mlocked=6988i,unevictable_pgs_mlockfreed=0i,unevictable_pgs_munlocked=6988i,unevictable_pgs_rescued=5426i,unevictable_pgs_scanned=0i,unevictable_pgs_stranded=0i,zone_reclaim_failed=0i 1459455200071462843
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
# Linux Sysctl FS Input
|
||||
|
||||
The linux_sysctl_fs input provides Linux system level file metrics. The documentation on these fields can be found at https://www.kernel.org/doc/Documentation/sysctl/fs.txt.
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
> linux_sysctl_fs,host=foo dentry-want-pages=0i,file-max=44222i,aio-max-nr=65536i,inode-preshrink-nr=0i,dentry-nr=64340i,dentry-unused-nr=55274i,file-nr=1568i,aio-nr=0i,inode-nr=35952i,inode-free-nr=12957i,dentry-age-limit=45i 1490982022000000000
|
||||
```
|
||||
@@ -1,35 +0,0 @@
|
||||
# Mem Input Plugin
|
||||
|
||||
The mem plugin collects system memory metrics.
|
||||
|
||||
For a more complete explanation of the difference between *used* and
|
||||
*actual_used* RAM, see [Linux ate my ram](http://www.linuxatemyram.com/).
|
||||
|
||||
### Configuration:
|
||||
```toml
|
||||
# Read metrics about memory usage
|
||||
[[inputs.mem]]
|
||||
# no configuration
|
||||
```
|
||||
|
||||
### Metrics:
|
||||
|
||||
- mem
|
||||
- fields:
|
||||
- active (int)
|
||||
- available (int)
|
||||
- buffered (int)
|
||||
- cached (int)
|
||||
- free (int)
|
||||
- inactive (int)
|
||||
- slab (int)
|
||||
- total (int)
|
||||
- used (int)
|
||||
- available_percent (float)
|
||||
- used_percent (float)
|
||||
- wired (int)
|
||||
|
||||
### Example Output:
|
||||
```
|
||||
mem cached=7809495040i,inactive=6348988416i,total=20855394304i,available=11378946048i,buffered=927199232i,active=11292905472i,slab=1351340032i,used_percent=45.43883523785713,available_percent=54.56116476214287,used=9476448256i,free=1715331072i 1511894782000000000
|
||||
```
|
||||
@@ -1,52 +0,0 @@
|
||||
Telegraf plugin: NETSTAT
|
||||
|
||||
#### Description
|
||||
|
||||
The NETSTAT plugin collects TCP connections state and UDP socket counts by using `lsof`.
|
||||
|
||||
Supported TCP Connection states are follows.
|
||||
|
||||
- established
|
||||
- syn_sent
|
||||
- syn_recv
|
||||
- fin_wait1
|
||||
- fin_wait2
|
||||
- time_wait
|
||||
- close
|
||||
- close_wait
|
||||
- last_ack
|
||||
- listen
|
||||
- closing
|
||||
- none
|
||||
|
||||
|
||||
# Measurements:
|
||||
### TCP Connection State measurements:
|
||||
|
||||
Meta:
|
||||
- units: counts
|
||||
|
||||
Measurement names:
|
||||
- tcp_established
|
||||
- tcp_syn_sent
|
||||
- tcp_syn_recv
|
||||
- tcp_fin_wait1
|
||||
- tcp_fin_wait2
|
||||
- tcp_time_wait
|
||||
- tcp_close
|
||||
- tcp_close_wait
|
||||
- tcp_last_ack
|
||||
- tcp_listen
|
||||
- tcp_closing
|
||||
- tcp_none
|
||||
|
||||
If there are no connection on the state, the metric is not counted.
|
||||
|
||||
### UDP socket counts measurements:
|
||||
|
||||
Meta:
|
||||
- units: counts
|
||||
|
||||
Measurement names:
|
||||
- udp_socket
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# Net Input Plugin
|
||||
|
||||
This plugin gathers metrics about network interface and protocol usage (Linux only).
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Gather metrics about network interfaces
|
||||
[[inputs.net]]
|
||||
## By default, telegraf gathers stats from any up interface (excluding loopback)
|
||||
## Setting interfaces will tell it to gather these explicit interfaces,
|
||||
## regardless of status. When specifying an interface, glob-style
|
||||
## patterns are also supported.
|
||||
##
|
||||
# interfaces = ["eth*", "enp0s[0-1]", "lo"]
|
||||
##
|
||||
## On linux systems telegraf also collects protocol stats.
|
||||
## Setting ignore_protocol_stats to true will skip reporting of protocol metrics.
|
||||
##
|
||||
# ignore_protocol_stats = false
|
||||
##
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
The fields from this plugin are gathered in the _net_ measurement.
|
||||
|
||||
Fields (all platforms):
|
||||
|
||||
* bytes_sent - The total number of bytes sent by the interface
|
||||
* bytes_recv - The total number of bytes received by the interface
|
||||
* packets_sent - The total number of packets sent by the interface
|
||||
* packets_recv - The total number of packets received by the interface
|
||||
* err_in - The total number of receive errors detected by the interface
|
||||
* err_out - The total number of transmit errors detected by the interface
|
||||
* drop_in - The total number of received packets dropped by the interface
|
||||
* drop_out - The total number of transmitted packets dropped by the interface
|
||||
|
||||
Different platforms gather the data above with different mechanisms. Telegraf uses the ([gopsutil](https://github.com/shirou/gopsutil)) package, which under Linux reads the /proc/net/dev file.
|
||||
Under freebsd/openbsd and darwin the plugin uses netstat.
|
||||
|
||||
Additionally, for the time being _only under Linux_, the plugin gathers system wide stats for different network protocols using /proc/net/snmp (tcp, udp, icmp, etc.).
|
||||
Explanation of the different metrics exposed by snmp is out of the scope of this document. The best way to find information would be tracing the constants in the Linux kernel source [here](http://lxr.free-electrons.com/source/net/ipv4/proc.c) and their usage. If /proc/net/snmp cannot be read for some reason, telegraf ignores the error silently.
|
||||
|
||||
### Tags:
|
||||
|
||||
* Net measurements have the following tags:
|
||||
- interface (the interface from which metrics are gathered)
|
||||
|
||||
Under Linux the system wide protocol metrics have the interface=all tag.
|
||||
|
||||
### Sample Queries:
|
||||
|
||||
You can use the following query to get the upload/download traffic rate per second for all interfaces in the last hour. The query uses the (derivative function)[https://docs.influxdata.com/influxdb/v1.2/query_language/functions#derivative] which calculates the rate of change between subsequent field values.
|
||||
|
||||
```
|
||||
SELECT derivative(first(bytes_recv), 1s) as "download bytes/sec", derivative(first(bytes_sent), 1s) as "upload bytes/sec" FROM net WHERE time > now() - 1h AND interface != 'all' GROUP BY time(10s), interface fill(0);
|
||||
```
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
# All platforms
|
||||
$ ./telegraf --config telegraf.conf --input-filter net --test
|
||||
net,interface=eth0,host=HOST bytes_sent=451838509i,bytes_recv=3284081640i,packets_sent=2663590i,packets_recv=3585442i,err_in=0i,err_out=0i,drop_in=4i,drop_out=0i 1492834180000000000
|
||||
```
|
||||
|
||||
```
|
||||
# Linux
|
||||
$ ./telegraf --config telegraf.conf --input-filter net --test
|
||||
net,interface=eth0,host=HOST bytes_sent=451838509i,bytes_recv=3284081640i,packets_sent=2663590i,packets_recv=3585442i,err_in=0i,err_out=0i,drop_in=4i,drop_out=0i 1492834180000000000
|
||||
net,interface=all,host=HOST ip_reasmfails=0i,icmp_insrcquenchs=0i,icmp_outtimestamps=0i,ip_inhdrerrors=0i,ip_inunknownprotos=0i,icmp_intimeexcds=10i,icmp_outaddrmasks=0i,icmp_indestunreachs=11005i,icmpmsg_outtype0=6i,tcp_retranssegs=14669i,udplite_outdatagrams=0i,ip_reasmtimeout=0i,ip_outnoroutes=2577i,ip_inaddrerrors=186i,icmp_outaddrmaskreps=0i,tcp_incsumerrors=0i,tcp_activeopens=55965i,ip_reasmoks=0i,icmp_inechos=6i,icmp_outdestunreachs=9417i,ip_reasmreqds=0i,icmp_outtimestampreps=0i,tcp_rtoalgorithm=1i,icmpmsg_intype3=11005i,icmpmsg_outtype69=129i,tcp_outsegs=2777459i,udplite_rcvbuferrors=0i,ip_fragoks=0i,icmp_inmsgs=13398i,icmp_outerrors=0i,tcp_outrsts=14951i,udplite_noports=0i,icmp_outmsgs=11517i,icmp_outechoreps=6i,icmpmsg_intype11=10i,icmp_inparmprobs=0i,ip_forwdatagrams=0i,icmp_inechoreps=1909i,icmp_outredirects=0i,icmp_intimestampreps=0i,icmpmsg_intype5=468i,tcp_rtomax=120000i,tcp_maxconn=-1i,ip_fragcreates=0i,ip_fragfails=0i,icmp_inredirects=468i,icmp_outtimeexcds=0i,icmp_outechos=1965i,icmp_inaddrmasks=0i,tcp_inerrs=389i,tcp_rtomin=200i,ip_defaultttl=64i,ip_outrequests=3366408i,ip_forwarding=2i,udp_incsumerrors=0i,udp_indatagrams=522136i,udplite_incsumerrors=0i,ip_outdiscards=871i,icmp_inerrors=958i,icmp_outsrcquenchs=0i,icmpmsg_intype0=1909i,tcp_insegs=3580226i,udp_outdatagrams=577265i,udp_rcvbuferrors=0i,udplite_sndbuferrors=0i,icmp_incsumerrors=0i,icmp_outparmprobs=0i,icmpmsg_outtype3=9417i,tcp_attemptfails=2652i,udplite_inerrors=0i,udplite_indatagrams=0i,ip_inreceives=4172969i,icmpmsg_outtype8=1965i,tcp_currestab=59i,udp_noports=5961i,ip_indelivers=4099279i,ip_indiscards=0i,tcp_estabresets=5818i,udp_sndbuferrors=3i,icmp_intimestamps=0i,icmpmsg_intype8=6i,udp_inerrors=0i,icmp_inaddrmaskreps=0i,tcp_passiveopens=452i 1492831540000000000
|
||||
``
|
||||
@@ -1,65 +0,0 @@
|
||||
# Processes Input Plugin
|
||||
|
||||
This plugin gathers info about the total number of processes and groups
|
||||
them by status (zombie, sleeping, running, etc.)
|
||||
|
||||
On linux this plugin requires access to procfs (/proc), on other OSes
|
||||
it requires access to execute `ps`.
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Get the number of processes and group them by status
|
||||
[[inputs.processes]]
|
||||
# no configuration
|
||||
```
|
||||
|
||||
Another possible configuration is to define an alternative path for resolving the /proc location.
|
||||
Using the environment variable `HOST_PROC` the plugin will retrieve process information from the specified location.
|
||||
|
||||
`docker run -v /proc:/rootfs/proc:ro -e HOST_PROC=/rootfs/proc`
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- processes
|
||||
- blocked (aka disk sleep or uninterruptible sleep)
|
||||
- running
|
||||
- sleeping
|
||||
- stopped
|
||||
- total
|
||||
- zombie
|
||||
- dead
|
||||
- wait (freebsd only)
|
||||
- idle (bsd and Linux 4+ only)
|
||||
- paging (linux only)
|
||||
- total_threads (linux only)
|
||||
|
||||
### Process State Mappings
|
||||
|
||||
Different OSes use slightly different State codes for their processes, these
|
||||
state codes are documented in `man ps`, and I will give a mapping of what major
|
||||
OS state codes correspond to in telegraf metrics:
|
||||
|
||||
```
|
||||
Linux FreeBSD Darwin meaning
|
||||
R R R running
|
||||
S S S sleeping
|
||||
Z Z Z zombie
|
||||
X none none dead
|
||||
T T T stopped
|
||||
I I I idle (sleeping for longer than about 20 seconds)
|
||||
D D,L U blocked (waiting in uninterruptible sleep, or locked)
|
||||
W W none paging (linux kernel < 2.6 only), wait (freebsd)
|
||||
```
|
||||
|
||||
### Tags:
|
||||
|
||||
None
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
$ telegraf --config ~/ws/telegraf.conf --input-filter processes --test
|
||||
* Plugin: processes, Collection 1
|
||||
> processes blocked=8i,running=1i,sleeping=265i,stopped=0i,total=274i,zombie=0i,dead=0i,paging=0i,total_threads=687i 1457478636980905042
|
||||
```
|
||||
@@ -1,30 +0,0 @@
|
||||
# Swap Input Plugin
|
||||
|
||||
The swap plugin collects system swap metrics.
|
||||
|
||||
For more information on what swap memory is, read [All about Linux swap space](https://www.linux.com/news/all-about-linux-swap-space).
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Read metrics about swap memory usage
|
||||
[[inputs.swap]]
|
||||
# no configuration
|
||||
```
|
||||
|
||||
### Metrics:
|
||||
|
||||
- swap
|
||||
- fields:
|
||||
- free (int)
|
||||
- total (int)
|
||||
- used (int)
|
||||
- used_percent (float)
|
||||
- in (int)
|
||||
- out (int)
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
swap total=20855394304i,used_percent=45.43883523785713,used=9476448256i,free=1715331072i 1511894782000000000
|
||||
```
|
||||
@@ -1,152 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
)
|
||||
|
||||
type CPUStats struct {
|
||||
ps PS
|
||||
lastStats map[string]cpu.TimesStat
|
||||
|
||||
PerCPU bool `toml:"percpu"`
|
||||
TotalCPU bool `toml:"totalcpu"`
|
||||
CollectCPUTime bool `toml:"collect_cpu_time"`
|
||||
ReportActive bool `toml:"report_active"`
|
||||
}
|
||||
|
||||
func NewCPUStats(ps PS) *CPUStats {
|
||||
return &CPUStats{
|
||||
ps: ps,
|
||||
CollectCPUTime: true,
|
||||
ReportActive: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (_ *CPUStats) Description() string {
|
||||
return "Read metrics about cpu usage"
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
## Whether to report per-cpu stats or not
|
||||
percpu = true
|
||||
## Whether to report total system cpu stats or not
|
||||
totalcpu = true
|
||||
## If true, collect raw CPU time metrics.
|
||||
collect_cpu_time = false
|
||||
## If true, compute and report the sum of all non-idle CPU states.
|
||||
report_active = false
|
||||
`
|
||||
|
||||
func (_ *CPUStats) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
|
||||
times, err := s.ps.CPUTimes(s.PerCPU, s.TotalCPU)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting CPU info: %s", err)
|
||||
}
|
||||
now := time.Now()
|
||||
|
||||
for _, cts := range times {
|
||||
tags := map[string]string{
|
||||
"cpu": cts.CPU,
|
||||
}
|
||||
|
||||
total := totalCpuTime(cts)
|
||||
active := activeCpuTime(cts)
|
||||
|
||||
if s.CollectCPUTime {
|
||||
// Add cpu time metrics
|
||||
fieldsC := map[string]interface{}{
|
||||
"time_user": cts.User,
|
||||
"time_system": cts.System,
|
||||
"time_idle": cts.Idle,
|
||||
"time_nice": cts.Nice,
|
||||
"time_iowait": cts.Iowait,
|
||||
"time_irq": cts.Irq,
|
||||
"time_softirq": cts.Softirq,
|
||||
"time_steal": cts.Steal,
|
||||
"time_guest": cts.Guest,
|
||||
"time_guest_nice": cts.GuestNice,
|
||||
}
|
||||
if s.ReportActive {
|
||||
fieldsC["time_active"] = activeCpuTime(cts)
|
||||
}
|
||||
acc.AddCounter("cpu", fieldsC, tags, now)
|
||||
}
|
||||
|
||||
// Add in percentage
|
||||
if len(s.lastStats) == 0 {
|
||||
// If it's the 1st gather, can't get CPU Usage stats yet
|
||||
continue
|
||||
}
|
||||
|
||||
lastCts, ok := s.lastStats[cts.CPU]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
lastTotal := totalCpuTime(lastCts)
|
||||
lastActive := activeCpuTime(lastCts)
|
||||
totalDelta := total - lastTotal
|
||||
|
||||
if totalDelta < 0 {
|
||||
err = fmt.Errorf("Error: current total CPU time is less than previous total CPU time")
|
||||
break
|
||||
}
|
||||
|
||||
if totalDelta == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldsG := map[string]interface{}{
|
||||
"usage_user": 100 * (cts.User - lastCts.User - (cts.Guest - lastCts.Guest)) / totalDelta,
|
||||
"usage_system": 100 * (cts.System - lastCts.System) / totalDelta,
|
||||
"usage_idle": 100 * (cts.Idle - lastCts.Idle) / totalDelta,
|
||||
"usage_nice": 100 * (cts.Nice - lastCts.Nice - (cts.GuestNice - lastCts.GuestNice)) / totalDelta,
|
||||
"usage_iowait": 100 * (cts.Iowait - lastCts.Iowait) / totalDelta,
|
||||
"usage_irq": 100 * (cts.Irq - lastCts.Irq) / totalDelta,
|
||||
"usage_softirq": 100 * (cts.Softirq - lastCts.Softirq) / totalDelta,
|
||||
"usage_steal": 100 * (cts.Steal - lastCts.Steal) / totalDelta,
|
||||
"usage_guest": 100 * (cts.Guest - lastCts.Guest) / totalDelta,
|
||||
"usage_guest_nice": 100 * (cts.GuestNice - lastCts.GuestNice) / totalDelta,
|
||||
}
|
||||
if s.ReportActive {
|
||||
fieldsG["usage_active"] = 100 * (active - lastActive) / totalDelta
|
||||
}
|
||||
acc.AddGauge("cpu", fieldsG, tags, now)
|
||||
}
|
||||
|
||||
s.lastStats = make(map[string]cpu.TimesStat)
|
||||
for _, cts := range times {
|
||||
s.lastStats[cts.CPU] = cts
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func totalCpuTime(t cpu.TimesStat) float64 {
|
||||
total := t.User + t.System + t.Nice + t.Iowait + t.Irq + t.Softirq + t.Steal +
|
||||
t.Idle
|
||||
return total
|
||||
}
|
||||
|
||||
func activeCpuTime(t cpu.TimesStat) float64 {
|
||||
active := totalCpuTime(t) - t.Idle
|
||||
return active
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("cpu", func() telegraf.Input {
|
||||
return &CPUStats{
|
||||
PerCPU: true,
|
||||
TotalCPU: true,
|
||||
ps: newSystemPS(),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/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.TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 8.8,
|
||||
System: 8.2,
|
||||
Idle: 80.1,
|
||||
Nice: 1.3,
|
||||
Iowait: 0.8389,
|
||||
Irq: 0.6,
|
||||
Softirq: 0.11,
|
||||
Steal: 0.0511,
|
||||
Guest: 3.1,
|
||||
GuestNice: 0.324,
|
||||
}
|
||||
|
||||
cts2 := cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 24.9, // increased by 16.1
|
||||
System: 10.9, // increased by 2.7
|
||||
Idle: 157.9798, // increased by 77.8798 (for total increase of 100)
|
||||
Nice: 3.5, // increased by 2.2
|
||||
Iowait: 0.929, // increased by 0.0901
|
||||
Irq: 1.2, // increased by 0.6
|
||||
Softirq: 0.31, // increased by 0.2
|
||||
Steal: 0.2812, // increased by 0.2301
|
||||
Guest: 11.4, // increased by 8.3
|
||||
GuestNice: 2.524, // increased by 2.2
|
||||
}
|
||||
|
||||
mps.On("CPUTimes").Return([]cpu.TimesStat{cts}, nil)
|
||||
|
||||
cs := NewCPUStats(&mps)
|
||||
|
||||
cputags := map[string]string{
|
||||
"cpu": "cpu0",
|
||||
}
|
||||
|
||||
err := cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Computed values are checked with delta > 0 because of floating point arithmatic
|
||||
// imprecision
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 8.8, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 8.2, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 80.1, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_active", 19.9, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 1.3, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.8389, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 0.6, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_softirq", 0.11, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_steal", 0.0511, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest", 3.1, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest_nice", 0.324, 0, cputags)
|
||||
|
||||
mps2 := MockPS{}
|
||||
mps2.On("CPUTimes").Return([]cpu.TimesStat{cts2}, nil)
|
||||
cs.ps = &mps2
|
||||
|
||||
// Should have added cpu percentages too
|
||||
err = cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 24.9, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 10.9, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 157.9798, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_active", 42.0202, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 3.5, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.929, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 1.2, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_softirq", 0.31, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_steal", 0.2812, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest", 11.4, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest_nice", 2.524, 0, cputags)
|
||||
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_user", 7.8, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_system", 2.7, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_idle", 77.8798, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_active", 22.1202, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_nice", 0, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_iowait", 0.0901, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_irq", 0.6, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_softirq", 0.2, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_steal", 0.2301, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_guest", 8.3, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_guest_nice", 2.2, 0.0005, cputags)
|
||||
}
|
||||
|
||||
// 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
|
||||
//
|
||||
// Parameters:
|
||||
// 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,
|
||||
field string,
|
||||
expectedValue float64,
|
||||
delta float64,
|
||||
tags map[string]string,
|
||||
) {
|
||||
var actualValue float64
|
||||
for _, pt := range acc.Metrics {
|
||||
if pt.Measurement == measurement {
|
||||
for fieldname, value := range pt.Fields {
|
||||
if fieldname == field {
|
||||
if value, ok := 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)
|
||||
}
|
||||
|
||||
// TestCPUCountChange tests that no errors are encountered if the number of
|
||||
// CPUs increases as reported with LXC.
|
||||
func TestCPUCountIncrease(t *testing.T) {
|
||||
var mps MockPS
|
||||
var mps2 MockPS
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
cs := NewCPUStats(&mps)
|
||||
|
||||
mps.On("CPUTimes").Return(
|
||||
[]cpu.TimesStat{
|
||||
cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
},
|
||||
}, nil)
|
||||
|
||||
err = cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
mps2.On("CPUTimes").Return(
|
||||
[]cpu.TimesStat{
|
||||
cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
},
|
||||
cpu.TimesStat{
|
||||
CPU: "cpu1",
|
||||
},
|
||||
}, nil)
|
||||
cs.ps = &mps2
|
||||
|
||||
err = cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// TestCPUTimesDecrease tests that telegraf continue to works after
|
||||
// CPU times decrease, which seems to occur when Linux system is suspended.
|
||||
func TestCPUTimesDecrease(t *testing.T) {
|
||||
var mps MockPS
|
||||
defer mps.AssertExpectations(t)
|
||||
var acc testutil.Accumulator
|
||||
|
||||
cts := cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 18,
|
||||
Idle: 80,
|
||||
Iowait: 2,
|
||||
}
|
||||
|
||||
cts2 := cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 38, // increased by 20
|
||||
Idle: 40, // decreased by 40
|
||||
Iowait: 1, // decreased by 1
|
||||
}
|
||||
|
||||
cts3 := cpu.TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 56, // increased by 18
|
||||
Idle: 120, // increased by 80
|
||||
Iowait: 3, // increased by 2
|
||||
}
|
||||
|
||||
mps.On("CPUTimes").Return([]cpu.TimesStat{cts}, nil)
|
||||
|
||||
cs := NewCPUStats(&mps)
|
||||
|
||||
cputags := map[string]string{
|
||||
"cpu": "cpu0",
|
||||
}
|
||||
|
||||
err := cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Computed values are checked with delta > 0 because of floating point arithmatic
|
||||
// imprecision
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 18, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 80, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 2, 0, cputags)
|
||||
|
||||
mps2 := MockPS{}
|
||||
mps2.On("CPUTimes").Return([]cpu.TimesStat{cts2}, nil)
|
||||
cs.ps = &mps2
|
||||
|
||||
// CPU times decreased. An error should be raised
|
||||
err = cs.Gather(&acc)
|
||||
require.Error(t, err)
|
||||
|
||||
mps3 := MockPS{}
|
||||
mps3.On("CPUTimes").Return([]cpu.TimesStat{cts3}, nil)
|
||||
cs.ps = &mps3
|
||||
|
||||
err = cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 56, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 120, 0, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 3, 0, cputags)
|
||||
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_user", 18, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_idle", 80, 0.0005, cputags)
|
||||
assertContainsTaggedFloat(t, &acc, "cpu", "usage_iowait", 2, 0.0005, cputags)
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type DiskStats struct {
|
||||
ps PS
|
||||
|
||||
// Legacy support
|
||||
Mountpoints []string
|
||||
|
||||
MountPoints []string
|
||||
IgnoreFS []string `toml:"ignore_fs"`
|
||||
}
|
||||
|
||||
func (_ *DiskStats) Description() string {
|
||||
return "Read metrics about disk usage by mount point"
|
||||
}
|
||||
|
||||
var diskSampleConfig = `
|
||||
## By default stats will be gathered for all mount points.
|
||||
## Set mount_points will restrict the stats to only the specified mount points.
|
||||
# mount_points = ["/"]
|
||||
|
||||
## Ignore mount points by filesystem type.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "overlay", "aufs", "squashfs"]
|
||||
`
|
||||
|
||||
func (_ *DiskStats) SampleConfig() string {
|
||||
return diskSampleConfig
|
||||
}
|
||||
|
||||
func (s *DiskStats) Gather(acc telegraf.Accumulator) error {
|
||||
// Legacy support:
|
||||
if len(s.Mountpoints) != 0 {
|
||||
s.MountPoints = s.Mountpoints
|
||||
}
|
||||
|
||||
disks, partitions, err := s.ps.DiskUsage(s.MountPoints, s.IgnoreFS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting disk usage info: %s", err)
|
||||
}
|
||||
|
||||
for i, du := range disks {
|
||||
if du.Total == 0 {
|
||||
// Skip dummy filesystem (procfs, cgroupfs, ...)
|
||||
continue
|
||||
}
|
||||
mountOpts := parseOptions(partitions[i].Opts)
|
||||
tags := map[string]string{
|
||||
"path": du.Path,
|
||||
"device": strings.Replace(partitions[i].Device, "/dev/", "", -1),
|
||||
"fstype": du.Fstype,
|
||||
"mode": mountOpts.Mode(),
|
||||
}
|
||||
var used_percent float64
|
||||
if du.Used+du.Free > 0 {
|
||||
used_percent = float64(du.Used) /
|
||||
(float64(du.Used) + float64(du.Free)) * 100
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"total": du.Total,
|
||||
"free": du.Free,
|
||||
"used": du.Used,
|
||||
"used_percent": used_percent,
|
||||
"inodes_total": du.InodesTotal,
|
||||
"inodes_free": du.InodesFree,
|
||||
"inodes_used": du.InodesUsed,
|
||||
}
|
||||
acc.AddGauge("disk", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type MountOptions []string
|
||||
|
||||
func (opts MountOptions) Mode() string {
|
||||
if opts.exists("rw") {
|
||||
return "rw"
|
||||
} else if opts.exists("ro") {
|
||||
return "ro"
|
||||
} else {
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (opts MountOptions) exists(opt string) bool {
|
||||
for _, o := range opts {
|
||||
if o == opt {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseOptions(opts string) MountOptions {
|
||||
return strings.Split(opts, ",")
|
||||
}
|
||||
|
||||
func init() {
|
||||
ps := newSystemPS()
|
||||
inputs.Add("disk", func() telegraf.Input {
|
||||
return &DiskStats{ps: ps}
|
||||
})
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type MockFileInfo struct {
|
||||
os.FileInfo
|
||||
}
|
||||
|
||||
func TestDiskUsage(t *testing.T) {
|
||||
mck := &mock.Mock{}
|
||||
mps := MockPSDisk{&systemPS{&mockDiskUsage{mck}}, mck}
|
||||
defer mps.AssertExpectations(t)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
psAll := []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro,noatime,nodiratime",
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: "rw,noatime,nodiratime,errors=remount-ro",
|
||||
},
|
||||
}
|
||||
duAll := []disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("Partitions", true).Return(psAll, nil)
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return("")
|
||||
mps.On("PSDiskUsage", "/").Return(&duAll[0], nil)
|
||||
mps.On("PSDiskUsage", "/home").Return(&duAll[1], nil)
|
||||
|
||||
err = (&DiskStats{ps: mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 14
|
||||
assert.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
"path": "/",
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
tags2 := map[string]string{
|
||||
"path": "/home",
|
||||
"fstype": "ext4",
|
||||
"device": "sdb",
|
||||
"mode": "rw",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
fields2 := map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
|
||||
// We expect 6 more DiskMetrics 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, expectedAllDiskMetrics+7, acc.NFields())
|
||||
|
||||
// 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*expectedAllDiskMetrics+7, acc.NFields())
|
||||
}
|
||||
|
||||
func TestDiskUsageHostMountPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
partitionStats []disk.PartitionStat
|
||||
usageStats []*disk.UsageStat
|
||||
hostMountPrefix string
|
||||
expectedTags map[string]string
|
||||
expectedFields map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no host mount prefix",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro",
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
&disk.UsageStat{
|
||||
Path: "/",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
expectedTags: map[string]string{
|
||||
"path": "/",
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "host mount prefix",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/hostfs/var",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro",
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
&disk.UsageStat{
|
||||
Path: "/hostfs/var",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
hostMountPrefix: "/hostfs",
|
||||
expectedTags: map[string]string{
|
||||
"path": "/var",
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "host mount prefix exact match",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/hostfs",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro",
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
&disk.UsageStat{
|
||||
Path: "/hostfs",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
hostMountPrefix: "/hostfs",
|
||||
expectedTags: map[string]string{
|
||||
"path": "/",
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mck := &mock.Mock{}
|
||||
mps := MockPSDisk{&systemPS{&mockDiskUsage{mck}}, mck}
|
||||
defer mps.AssertExpectations(t)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
mps.On("Partitions", true).Return(tt.partitionStats, nil)
|
||||
|
||||
for _, v := range tt.usageStats {
|
||||
mps.On("PSDiskUsage", v.Path).Return(v, nil)
|
||||
}
|
||||
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return(tt.hostMountPrefix)
|
||||
|
||||
err = (&DiskStats{ps: mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "disk", tt.expectedFields, tt.expectedTags)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiskStats(t *testing.T) {
|
||||
var mps MockPS
|
||||
defer mps.AssertExpectations(t)
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
duAll := []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
}
|
||||
duFiltered := []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
|
||||
psAll := []*disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro,noatime,nodiratime",
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: "rw,noatime,nodiratime,errors=remount-ro",
|
||||
},
|
||||
}
|
||||
|
||||
psFiltered := []*disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: "ro,noatime,nodiratime",
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("DiskUsage", []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/dev"}, []string(nil)).Return(duFiltered, psFiltered, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/home"}, []string(nil)).Return(duAll, psAll, nil)
|
||||
|
||||
err = (&DiskStats{ps: &mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 14
|
||||
assert.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
"path": "/",
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
tags2 := map[string]string{
|
||||
"path": "/home",
|
||||
"fstype": "ext4",
|
||||
"device": "sdb",
|
||||
"mode": "rw",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
fields2 := map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
|
||||
// We expect 6 more DiskMetrics 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, expectedAllDiskMetrics+7, acc.NFields())
|
||||
|
||||
// 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*expectedAllDiskMetrics+7, acc.NFields())
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
var (
|
||||
varRegex = regexp.MustCompile(`\$(?:\w+|\{\w+\})`)
|
||||
)
|
||||
|
||||
type DiskIO struct {
|
||||
ps PS
|
||||
|
||||
Devices []string
|
||||
DeviceTags []string
|
||||
NameTemplates []string
|
||||
SkipSerialNumber bool
|
||||
|
||||
infoCache map[string]diskInfoCache
|
||||
deviceFilter filter.Filter
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func (_ *DiskIO) Description() string {
|
||||
return "Read metrics about disk IO by device"
|
||||
}
|
||||
|
||||
var diskIOsampleConfig = `
|
||||
## By default, telegraf will gather stats for all devices including
|
||||
## disk partitions.
|
||||
## Setting devices will restrict the stats to the specified devices.
|
||||
# devices = ["sda", "sdb", "vd*"]
|
||||
## Uncomment the following line if you need disk serial numbers.
|
||||
# skip_serial_number = false
|
||||
#
|
||||
## On systems which support it, device metadata can be added in the form of
|
||||
## tags.
|
||||
## Currently only Linux is supported via udev properties. You can view
|
||||
## available properties for a device by running:
|
||||
## 'udevadm info -q property -n /dev/sda'
|
||||
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
||||
#
|
||||
## Using the same metadata source as device_tags, you can also customize the
|
||||
## name of the device via templates.
|
||||
## The 'name_templates' parameter is a list of templates to try and apply to
|
||||
## the device. The template may contain variables in the form of '$PROPERTY' or
|
||||
## '${PROPERTY}'. The first template which does not contain any variables not
|
||||
## present for the device is used as the device name tag.
|
||||
## The typical use case is for LVM volumes, to get the VG/LV name instead of
|
||||
## the near-meaningless DM-0 name.
|
||||
# name_templates = ["$ID_FS_LABEL","$DM_VG_NAME/$DM_LV_NAME"]
|
||||
`
|
||||
|
||||
func (_ *DiskIO) SampleConfig() string {
|
||||
return diskIOsampleConfig
|
||||
}
|
||||
|
||||
// hasMeta reports whether s contains any special glob characters.
|
||||
func hasMeta(s string) bool {
|
||||
return strings.IndexAny(s, "*?[") >= 0
|
||||
}
|
||||
|
||||
func (s *DiskIO) init() error {
|
||||
for _, device := range s.Devices {
|
||||
if hasMeta(device) {
|
||||
filter, err := filter.Compile(s.Devices)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error compiling device pattern: %v", err)
|
||||
}
|
||||
s.deviceFilter = filter
|
||||
}
|
||||
}
|
||||
s.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DiskIO) Gather(acc telegraf.Accumulator) error {
|
||||
if !s.initialized {
|
||||
err := s.init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
devices := []string{}
|
||||
if s.deviceFilter == nil {
|
||||
devices = s.Devices
|
||||
}
|
||||
|
||||
diskio, err := s.ps.DiskIO(devices)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting disk io info: %s", err)
|
||||
}
|
||||
|
||||
for _, io := range diskio {
|
||||
if s.deviceFilter != nil && !s.deviceFilter.Match(io.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
tags := map[string]string{}
|
||||
tags["name"] = s.diskName(io.Name)
|
||||
for t, v := range s.diskTags(io.Name) {
|
||||
tags[t] = v
|
||||
}
|
||||
if !s.SkipSerialNumber {
|
||||
if len(io.SerialNumber) != 0 {
|
||||
tags["serial"] = io.SerialNumber
|
||||
} else {
|
||||
tags["serial"] = "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"reads": io.ReadCount,
|
||||
"writes": io.WriteCount,
|
||||
"read_bytes": io.ReadBytes,
|
||||
"write_bytes": io.WriteBytes,
|
||||
"read_time": io.ReadTime,
|
||||
"write_time": io.WriteTime,
|
||||
"io_time": io.IoTime,
|
||||
"weighted_io_time": io.WeightedIO,
|
||||
"iops_in_progress": io.IopsInProgress,
|
||||
}
|
||||
acc.AddCounter("diskio", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DiskIO) diskName(devName string) string {
|
||||
if len(s.NameTemplates) == 0 {
|
||||
return devName
|
||||
}
|
||||
|
||||
di, err := s.diskInfo(devName)
|
||||
if err != nil {
|
||||
log.Printf("W! Error gathering disk info: %s", err)
|
||||
return devName
|
||||
}
|
||||
|
||||
for _, nt := range s.NameTemplates {
|
||||
miss := false
|
||||
name := varRegex.ReplaceAllStringFunc(nt, func(sub string) string {
|
||||
sub = sub[1:] // strip leading '$'
|
||||
if sub[0] == '{' {
|
||||
sub = sub[1 : len(sub)-1] // strip leading & trailing '{' '}'
|
||||
}
|
||||
if v, ok := di[sub]; ok {
|
||||
return v
|
||||
}
|
||||
miss = true
|
||||
return ""
|
||||
})
|
||||
|
||||
if !miss {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
return devName
|
||||
}
|
||||
|
||||
func (s *DiskIO) diskTags(devName string) map[string]string {
|
||||
if len(s.DeviceTags) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
di, err := s.diskInfo(devName)
|
||||
if err != nil {
|
||||
log.Printf("W! Error gathering disk info: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
tags := map[string]string{}
|
||||
for _, dt := range s.DeviceTags {
|
||||
if v, ok := di[dt]; ok {
|
||||
tags[dt] = v
|
||||
}
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
func init() {
|
||||
ps := newSystemPS()
|
||||
inputs.Add("diskio", func() telegraf.Input {
|
||||
return &DiskIO{ps: ps, SkipSerialNumber: true}
|
||||
})
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type diskInfoCache struct {
|
||||
udevDataPath string
|
||||
values map[string]string
|
||||
}
|
||||
|
||||
var udevPath = "/run/udev/data"
|
||||
|
||||
func (s *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
||||
var err error
|
||||
var stat unix.Stat_t
|
||||
|
||||
path := "/dev/" + devName
|
||||
err = unix.Stat(path, &stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.infoCache == nil {
|
||||
s.infoCache = map[string]diskInfoCache{}
|
||||
}
|
||||
ic, ok := s.infoCache[devName]
|
||||
if ok {
|
||||
return ic.values, nil
|
||||
}
|
||||
|
||||
major := stat.Rdev >> 8 & 0xff
|
||||
minor := stat.Rdev & 0xff
|
||||
udevDataPath := fmt.Sprintf("%s/b%d:%d", udevPath, major, minor)
|
||||
|
||||
di := map[string]string{}
|
||||
|
||||
s.infoCache[devName] = diskInfoCache{
|
||||
udevDataPath: udevDataPath,
|
||||
values: di,
|
||||
}
|
||||
|
||||
f, err := os.Open(udevDataPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scnr := bufio.NewScanner(f)
|
||||
for scnr.Scan() {
|
||||
l := scnr.Text()
|
||||
if len(l) < 4 || l[:2] != "E:" {
|
||||
continue
|
||||
}
|
||||
kv := strings.SplitN(l[2:], "=", 2)
|
||||
if len(kv) < 2 {
|
||||
continue
|
||||
}
|
||||
di[kv[0]] = kv[1]
|
||||
}
|
||||
|
||||
return di, nil
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var nullDiskInfo = []byte(`
|
||||
E:MY_PARAM_1=myval1
|
||||
E:MY_PARAM_2=myval2
|
||||
`)
|
||||
|
||||
// setupNullDisk sets up fake udev info as if /dev/null were a disk.
|
||||
func setupNullDisk(t *testing.T) func() error {
|
||||
td, err := ioutil.TempDir("", ".telegraf.TestDiskInfo")
|
||||
require.NoError(t, err)
|
||||
|
||||
origUdevPath := udevPath
|
||||
|
||||
cleanFunc := func() error {
|
||||
udevPath = origUdevPath
|
||||
return os.RemoveAll(td)
|
||||
}
|
||||
|
||||
udevPath = td
|
||||
err = ioutil.WriteFile(td+"/b1:3", nullDiskInfo, 0644) // 1:3 is the 'null' device
|
||||
if err != nil {
|
||||
cleanFunc()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return cleanFunc
|
||||
}
|
||||
|
||||
func TestDiskInfo(t *testing.T) {
|
||||
clean := setupNullDisk(t)
|
||||
defer clean()
|
||||
|
||||
s := &DiskIO{}
|
||||
di, err := s.diskInfo("null")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "myval1", di["MY_PARAM_1"])
|
||||
assert.Equal(t, "myval2", di["MY_PARAM_2"])
|
||||
|
||||
// test that data is cached
|
||||
err = clean()
|
||||
require.NoError(t, err)
|
||||
|
||||
di, err = s.diskInfo("null")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "myval1", di["MY_PARAM_1"])
|
||||
assert.Equal(t, "myval2", di["MY_PARAM_2"])
|
||||
|
||||
// unfortunately we can't adjust mtime on /dev/null to test cache invalidation
|
||||
}
|
||||
|
||||
// DiskIOStats.diskName isn't a linux specific function, but dependent
|
||||
// functions are a no-op on non-Linux.
|
||||
func TestDiskIOStats_diskName(t *testing.T) {
|
||||
defer setupNullDisk(t)()
|
||||
|
||||
tests := []struct {
|
||||
templates []string
|
||||
expected string
|
||||
}{
|
||||
{[]string{"$MY_PARAM_1"}, "myval1"},
|
||||
{[]string{"${MY_PARAM_1}"}, "myval1"},
|
||||
{[]string{"x$MY_PARAM_1"}, "xmyval1"},
|
||||
{[]string{"x${MY_PARAM_1}x"}, "xmyval1x"},
|
||||
{[]string{"$MISSING", "$MY_PARAM_1"}, "myval1"},
|
||||
{[]string{"$MY_PARAM_1", "$MY_PARAM_2"}, "myval1"},
|
||||
{[]string{"$MISSING"}, "null"},
|
||||
{[]string{"$MY_PARAM_1/$MY_PARAM_2"}, "myval1/myval2"},
|
||||
{[]string{"$MY_PARAM_2/$MISSING"}, "null"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
s := DiskIO{
|
||||
NameTemplates: tc.templates,
|
||||
}
|
||||
assert.Equal(t, tc.expected, s.diskName("null"), "Templates: %#v", tc.templates)
|
||||
}
|
||||
}
|
||||
|
||||
// DiskIOStats.diskTags isn't a linux specific function, but dependent
|
||||
// functions are a no-op on non-Linux.
|
||||
func TestDiskIOStats_diskTags(t *testing.T) {
|
||||
defer setupNullDisk(t)()
|
||||
|
||||
s := &DiskIO{
|
||||
DeviceTags: []string{"MY_PARAM_2"},
|
||||
}
|
||||
dt := s.diskTags("null")
|
||||
assert.Equal(t, map[string]string{"MY_PARAM_2": "myval2"}, dt)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package system
|
||||
|
||||
type diskInfoCache struct{}
|
||||
|
||||
func (s *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDiskIO(t *testing.T) {
|
||||
type Result struct {
|
||||
stats map[string]disk.IOCountersStat
|
||||
err error
|
||||
}
|
||||
type Metric struct {
|
||||
tags map[string]string
|
||||
fields map[string]interface{}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
devices []string
|
||||
result Result
|
||||
err error
|
||||
metrics []Metric
|
||||
}{
|
||||
{
|
||||
name: "minimal",
|
||||
result: Result{
|
||||
stats: map[string]disk.IOCountersStat{
|
||||
"sda": disk.IOCountersStat{
|
||||
ReadCount: 888,
|
||||
WriteCount: 5341,
|
||||
ReadBytes: 100000,
|
||||
WriteBytes: 200000,
|
||||
ReadTime: 7123,
|
||||
WriteTime: 9087,
|
||||
Name: "sda",
|
||||
IoTime: 123552,
|
||||
SerialNumber: "ab-123-ad",
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
err: nil,
|
||||
metrics: []Metric{
|
||||
Metric{
|
||||
tags: map[string]string{
|
||||
"name": "sda",
|
||||
"serial": "ab-123-ad",
|
||||
},
|
||||
fields: map[string]interface{}{
|
||||
"reads": uint64(888),
|
||||
"writes": uint64(5341),
|
||||
"read_bytes": uint64(100000),
|
||||
"write_bytes": uint64(200000),
|
||||
"read_time": uint64(7123),
|
||||
"write_time": uint64(9087),
|
||||
"io_time": uint64(123552),
|
||||
"weighted_io_time": uint64(0),
|
||||
"iops_in_progress": uint64(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "glob device",
|
||||
devices: []string{"sd*"},
|
||||
result: Result{
|
||||
stats: map[string]disk.IOCountersStat{
|
||||
"sda": disk.IOCountersStat{
|
||||
Name: "sda",
|
||||
ReadCount: 42,
|
||||
},
|
||||
"vda": disk.IOCountersStat{
|
||||
Name: "vda",
|
||||
ReadCount: 42,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
err: nil,
|
||||
metrics: []Metric{
|
||||
Metric{
|
||||
tags: map[string]string{
|
||||
"name": "sda",
|
||||
"serial": "unknown",
|
||||
},
|
||||
fields: map[string]interface{}{
|
||||
"reads": uint64(42),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var mps MockPS
|
||||
mps.On("DiskIO").Return(tt.result.stats, tt.result.err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
diskio := &DiskIO{
|
||||
ps: &mps,
|
||||
Devices: tt.devices,
|
||||
}
|
||||
err := diskio.Gather(&acc)
|
||||
require.Equal(t, tt.err, err)
|
||||
|
||||
for _, metric := range tt.metrics {
|
||||
for k, v := range metric.fields {
|
||||
require.True(t, acc.HasPoint("diskio", metric.tags, k, v),
|
||||
"missing point: diskio %v %q: %v", metric.tags, k, v)
|
||||
}
|
||||
}
|
||||
require.Equal(t, len(tt.metrics), int(acc.NMetrics()), "unexpected number of metrics")
|
||||
require.True(t, mps.AssertExpectations(t))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
// /proc/stat file line prefixes to gather stats on:
|
||||
var (
|
||||
interrupts = []byte("intr")
|
||||
context_switches = []byte("ctxt")
|
||||
processes_forked = []byte("processes")
|
||||
disk_pages = []byte("page")
|
||||
boot_time = []byte("btime")
|
||||
)
|
||||
|
||||
type Kernel struct {
|
||||
statFile string
|
||||
entropyStatFile string
|
||||
}
|
||||
|
||||
func (k *Kernel) Description() string {
|
||||
return "Get kernel statistics from /proc/stat"
|
||||
}
|
||||
|
||||
func (k *Kernel) SampleConfig() string { return "" }
|
||||
|
||||
func (k *Kernel) Gather(acc telegraf.Accumulator) error {
|
||||
|
||||
data, err := k.getProcStat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entropyData, err := ioutil.ReadFile(k.entropyStatFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entropyString := string(entropyData)
|
||||
entropyValue, err := strconv.ParseInt(strings.TrimSpace(entropyString), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := make(map[string]interface{})
|
||||
|
||||
fields["entropy_avail"] = int64(entropyValue)
|
||||
|
||||
dataFields := bytes.Fields(data)
|
||||
for i, field := range dataFields {
|
||||
switch {
|
||||
case bytes.Equal(field, interrupts):
|
||||
m, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields["interrupts"] = int64(m)
|
||||
case bytes.Equal(field, context_switches):
|
||||
m, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields["context_switches"] = int64(m)
|
||||
case bytes.Equal(field, processes_forked):
|
||||
m, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields["processes_forked"] = int64(m)
|
||||
case bytes.Equal(field, boot_time):
|
||||
m, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields["boot_time"] = int64(m)
|
||||
case bytes.Equal(field, disk_pages):
|
||||
in, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := strconv.ParseInt(string(dataFields[i+2]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields["disk_pages_in"] = int64(in)
|
||||
fields["disk_pages_out"] = int64(out)
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddCounter("kernel", fields, map[string]string{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *Kernel) getProcStat() ([]byte, error) {
|
||||
if _, err := os.Stat(k.statFile); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("kernel: %s does not exist!", k.statFile)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(k.statFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("kernel", func() telegraf.Input {
|
||||
return &Kernel{
|
||||
statFile: "/proc/stat",
|
||||
entropyStatFile: "/proc/sys/kernel/random/entropy_avail",
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type Kernel struct {
|
||||
}
|
||||
|
||||
func (k *Kernel) Description() string {
|
||||
return "Get kernel statistics from /proc/stat"
|
||||
}
|
||||
|
||||
func (k *Kernel) SampleConfig() string { return "" }
|
||||
|
||||
func (k *Kernel) Gather(acc telegraf.Accumulator) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("kernel", func() telegraf.Input {
|
||||
return &Kernel{}
|
||||
})
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFullProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(statFile_Full))
|
||||
tmpfile2 := makeFakeStatFile([]byte(entropyStatFile_Full))
|
||||
defer os.Remove(tmpfile)
|
||||
defer os.Remove(tmpfile2)
|
||||
|
||||
k := Kernel{
|
||||
statFile: tmpfile,
|
||||
entropyStatFile: tmpfile2,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"boot_time": int64(1457505775),
|
||||
"context_switches": int64(2626618),
|
||||
"disk_pages_in": int64(5741),
|
||||
"disk_pages_out": int64(1808),
|
||||
"interrupts": int64(1472736),
|
||||
"processes_forked": int64(10673),
|
||||
"entropy_avail": int64(1024),
|
||||
}
|
||||
acc.AssertContainsFields(t, "kernel", fields)
|
||||
}
|
||||
|
||||
func TestPartialProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(statFile_Partial))
|
||||
tmpfile2 := makeFakeStatFile([]byte(entropyStatFile_Partial))
|
||||
defer os.Remove(tmpfile)
|
||||
defer os.Remove(tmpfile2)
|
||||
|
||||
k := Kernel{
|
||||
statFile: tmpfile,
|
||||
entropyStatFile: tmpfile2,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"boot_time": int64(1457505775),
|
||||
"context_switches": int64(2626618),
|
||||
"disk_pages_in": int64(5741),
|
||||
"disk_pages_out": int64(1808),
|
||||
"interrupts": int64(1472736),
|
||||
"entropy_avail": int64(1024),
|
||||
}
|
||||
acc.AssertContainsFields(t, "kernel", fields)
|
||||
}
|
||||
|
||||
func TestInvalidProcFile1(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(statFile_Invalid))
|
||||
tmpfile2 := makeFakeStatFile([]byte(entropyStatFile_Invalid))
|
||||
defer os.Remove(tmpfile)
|
||||
defer os.Remove(tmpfile2)
|
||||
|
||||
k := Kernel{
|
||||
statFile: tmpfile,
|
||||
entropyStatFile: tmpfile2,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestInvalidProcFile2(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(statFile_Invalid2))
|
||||
defer os.Remove(tmpfile)
|
||||
|
||||
k := Kernel{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNoProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(statFile_Invalid2))
|
||||
os.Remove(tmpfile)
|
||||
|
||||
k := Kernel{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "does not exist")
|
||||
}
|
||||
|
||||
const statFile_Full = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 2626618
|
||||
btime 1457505775
|
||||
processes 10673
|
||||
procs_running 2
|
||||
procs_blocked 0
|
||||
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||
page 5741 1808
|
||||
swap 1 0
|
||||
entropy_avail 1024
|
||||
`
|
||||
|
||||
const statFile_Partial = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 2626618
|
||||
btime 1457505775
|
||||
procs_running 2
|
||||
procs_blocked 0
|
||||
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||
page 5741 1808
|
||||
`
|
||||
|
||||
// missing btime measurement
|
||||
const statFile_Invalid = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 2626618
|
||||
btime
|
||||
processes 10673
|
||||
procs_running 2
|
||||
procs_blocked 0
|
||||
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||
page 5741 1808
|
||||
swap 1 0
|
||||
entropy_avail 1024
|
||||
`
|
||||
|
||||
// missing second page measurement
|
||||
const statFile_Invalid2 = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 2626618
|
||||
processes 10673
|
||||
procs_running 2
|
||||
page 5741
|
||||
procs_blocked 0
|
||||
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||
entropy_avail 1024 2048
|
||||
`
|
||||
|
||||
const entropyStatFile_Full = `1024`
|
||||
|
||||
const entropyStatFile_Partial = `1024`
|
||||
|
||||
const entropyStatFile_Invalid = ``
|
||||
|
||||
func makeFakeStatFile(content []byte) string {
|
||||
tmpfile, err := ioutil.TempFile("", "kerneltest")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tmpfile.Name()
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type KernelVmstat struct {
|
||||
statFile string
|
||||
}
|
||||
|
||||
func (k *KernelVmstat) Description() string {
|
||||
return "Get kernel statistics from /proc/vmstat"
|
||||
}
|
||||
|
||||
func (k *KernelVmstat) SampleConfig() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (k *KernelVmstat) Gather(acc telegraf.Accumulator) error {
|
||||
data, err := k.getProcVmstat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := make(map[string]interface{})
|
||||
|
||||
dataFields := bytes.Fields(data)
|
||||
for i, field := range dataFields {
|
||||
|
||||
// dataFields is an array of {"stat1_name", "stat1_value", "stat2_name",
|
||||
// "stat2_value", ...}
|
||||
// We only want the even number index as that contain the stat name.
|
||||
if i%2 == 0 {
|
||||
// Convert the stat value into an integer.
|
||||
m, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields[string(field)] = int64(m)
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddFields("kernel_vmstat", fields, map[string]string{})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KernelVmstat) getProcVmstat() ([]byte, error) {
|
||||
if _, err := os.Stat(k.statFile); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("kernel_vmstat: %s does not exist!", k.statFile)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(k.statFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("kernel_vmstat", func() telegraf.Input {
|
||||
return &KernelVmstat{
|
||||
statFile: "/proc/vmstat",
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFullVmStatProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(vmStatFile_Full))
|
||||
defer os.Remove(tmpfile)
|
||||
|
||||
k := KernelVmstat{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"nr_free_pages": int64(78730),
|
||||
"nr_inactive_anon": int64(426259),
|
||||
"nr_active_anon": int64(2515657),
|
||||
"nr_inactive_file": int64(2366791),
|
||||
"nr_active_file": int64(2244914),
|
||||
"nr_unevictable": int64(0),
|
||||
"nr_mlock": int64(0),
|
||||
"nr_anon_pages": int64(1358675),
|
||||
"nr_mapped": int64(558821),
|
||||
"nr_file_pages": int64(5153546),
|
||||
"nr_dirty": int64(5690),
|
||||
"nr_writeback": int64(0),
|
||||
"nr_slab_reclaimable": int64(459806),
|
||||
"nr_slab_unreclaimable": int64(47859),
|
||||
"nr_page_table_pages": int64(11115),
|
||||
"nr_kernel_stack": int64(579),
|
||||
"nr_unstable": int64(0),
|
||||
"nr_bounce": int64(0),
|
||||
"nr_vmscan_write": int64(6206),
|
||||
"nr_writeback_temp": int64(0),
|
||||
"nr_isolated_anon": int64(0),
|
||||
"nr_isolated_file": int64(0),
|
||||
"nr_shmem": int64(541689),
|
||||
"numa_hit": int64(6690743595),
|
||||
"numa_miss": int64(0),
|
||||
"numa_foreign": int64(0),
|
||||
"numa_interleave": int64(35793),
|
||||
"numa_local": int64(5113399878),
|
||||
"numa_other": int64(0),
|
||||
"nr_anon_transparent_hugepages": int64(2034),
|
||||
"pgpgin": int64(219717626),
|
||||
"pgpgout": int64(3495885510),
|
||||
"pswpin": int64(2092),
|
||||
"pswpout": int64(6206),
|
||||
"pgalloc_dma": int64(0),
|
||||
"pgalloc_dma32": int64(122480220),
|
||||
"pgalloc_normal": int64(5233176719),
|
||||
"pgalloc_movable": int64(0),
|
||||
"pgfree": int64(5359765021),
|
||||
"pgactivate": int64(375664931),
|
||||
"pgdeactivate": int64(122735906),
|
||||
"pgfault": int64(8699921410),
|
||||
"pgmajfault": int64(122210),
|
||||
"pgrefill_dma": int64(0),
|
||||
"pgrefill_dma32": int64(1180010),
|
||||
"pgrefill_normal": int64(119866676),
|
||||
"pgrefill_movable": int64(0),
|
||||
"pgsteal_dma": int64(0),
|
||||
"pgsteal_dma32": int64(4466436),
|
||||
"pgsteal_normal": int64(318463755),
|
||||
"pgsteal_movable": int64(0),
|
||||
"pgscan_kswapd_dma": int64(0),
|
||||
"pgscan_kswapd_dma32": int64(4480608),
|
||||
"pgscan_kswapd_normal": int64(287857984),
|
||||
"pgscan_kswapd_movable": int64(0),
|
||||
"pgscan_direct_dma": int64(0),
|
||||
"pgscan_direct_dma32": int64(12256),
|
||||
"pgscan_direct_normal": int64(31501600),
|
||||
"pgscan_direct_movable": int64(0),
|
||||
"zone_reclaim_failed": int64(0),
|
||||
"pginodesteal": int64(9188431),
|
||||
"slabs_scanned": int64(93775616),
|
||||
"kswapd_steal": int64(291534428),
|
||||
"kswapd_inodesteal": int64(29770874),
|
||||
"kswapd_low_wmark_hit_quickly": int64(8756),
|
||||
"kswapd_high_wmark_hit_quickly": int64(25439),
|
||||
"kswapd_skip_congestion_wait": int64(0),
|
||||
"pageoutrun": int64(505006),
|
||||
"allocstall": int64(81496),
|
||||
"pgrotated": int64(60620),
|
||||
"compact_blocks_moved": int64(238196),
|
||||
"compact_pages_moved": int64(6370588),
|
||||
"compact_pagemigrate_failed": int64(0),
|
||||
"compact_stall": int64(142092),
|
||||
"compact_fail": int64(135220),
|
||||
"compact_success": int64(6872),
|
||||
"htlb_buddy_alloc_success": int64(0),
|
||||
"htlb_buddy_alloc_fail": int64(0),
|
||||
"unevictable_pgs_culled": int64(1531),
|
||||
"unevictable_pgs_scanned": int64(0),
|
||||
"unevictable_pgs_rescued": int64(5426),
|
||||
"unevictable_pgs_mlocked": int64(6988),
|
||||
"unevictable_pgs_munlocked": int64(6988),
|
||||
"unevictable_pgs_cleared": int64(0),
|
||||
"unevictable_pgs_stranded": int64(0),
|
||||
"unevictable_pgs_mlockfreed": int64(0),
|
||||
"thp_fault_alloc": int64(346219),
|
||||
"thp_fault_fallback": int64(895453),
|
||||
"thp_collapse_alloc": int64(24857),
|
||||
"thp_collapse_alloc_failed": int64(102214),
|
||||
"thp_split": int64(9817),
|
||||
}
|
||||
acc.AssertContainsFields(t, "kernel_vmstat", fields)
|
||||
}
|
||||
|
||||
func TestPartialVmStatProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(vmStatFile_Partial))
|
||||
defer os.Remove(tmpfile)
|
||||
|
||||
k := KernelVmstat{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"unevictable_pgs_culled": int64(1531),
|
||||
"unevictable_pgs_scanned": int64(0),
|
||||
"unevictable_pgs_rescued": int64(5426),
|
||||
"unevictable_pgs_mlocked": int64(6988),
|
||||
"unevictable_pgs_munlocked": int64(6988),
|
||||
"unevictable_pgs_cleared": int64(0),
|
||||
"unevictable_pgs_stranded": int64(0),
|
||||
"unevictable_pgs_mlockfreed": int64(0),
|
||||
"thp_fault_alloc": int64(346219),
|
||||
"thp_fault_fallback": int64(895453),
|
||||
"thp_collapse_alloc": int64(24857),
|
||||
"thp_collapse_alloc_failed": int64(102214),
|
||||
"thp_split": int64(9817),
|
||||
}
|
||||
acc.AssertContainsFields(t, "kernel_vmstat", fields)
|
||||
}
|
||||
|
||||
func TestInvalidVmStatProcFile1(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(vmStatFile_Invalid))
|
||||
defer os.Remove(tmpfile)
|
||||
|
||||
k := KernelVmstat{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNoVmStatProcFile(t *testing.T) {
|
||||
tmpfile := makeFakeStatFile([]byte(vmStatFile_Invalid))
|
||||
os.Remove(tmpfile)
|
||||
|
||||
k := KernelVmstat{
|
||||
statFile: tmpfile,
|
||||
}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
err := k.Gather(&acc)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "does not exist")
|
||||
}
|
||||
|
||||
const vmStatFile_Full = `nr_free_pages 78730
|
||||
nr_inactive_anon 426259
|
||||
nr_active_anon 2515657
|
||||
nr_inactive_file 2366791
|
||||
nr_active_file 2244914
|
||||
nr_unevictable 0
|
||||
nr_mlock 0
|
||||
nr_anon_pages 1358675
|
||||
nr_mapped 558821
|
||||
nr_file_pages 5153546
|
||||
nr_dirty 5690
|
||||
nr_writeback 0
|
||||
nr_slab_reclaimable 459806
|
||||
nr_slab_unreclaimable 47859
|
||||
nr_page_table_pages 11115
|
||||
nr_kernel_stack 579
|
||||
nr_unstable 0
|
||||
nr_bounce 0
|
||||
nr_vmscan_write 6206
|
||||
nr_writeback_temp 0
|
||||
nr_isolated_anon 0
|
||||
nr_isolated_file 0
|
||||
nr_shmem 541689
|
||||
numa_hit 6690743595
|
||||
numa_miss 0
|
||||
numa_foreign 0
|
||||
numa_interleave 35793
|
||||
numa_local 5113399878
|
||||
numa_other 0
|
||||
nr_anon_transparent_hugepages 2034
|
||||
pgpgin 219717626
|
||||
pgpgout 3495885510
|
||||
pswpin 2092
|
||||
pswpout 6206
|
||||
pgalloc_dma 0
|
||||
pgalloc_dma32 122480220
|
||||
pgalloc_normal 5233176719
|
||||
pgalloc_movable 0
|
||||
pgfree 5359765021
|
||||
pgactivate 375664931
|
||||
pgdeactivate 122735906
|
||||
pgfault 8699921410
|
||||
pgmajfault 122210
|
||||
pgrefill_dma 0
|
||||
pgrefill_dma32 1180010
|
||||
pgrefill_normal 119866676
|
||||
pgrefill_movable 0
|
||||
pgsteal_dma 0
|
||||
pgsteal_dma32 4466436
|
||||
pgsteal_normal 318463755
|
||||
pgsteal_movable 0
|
||||
pgscan_kswapd_dma 0
|
||||
pgscan_kswapd_dma32 4480608
|
||||
pgscan_kswapd_normal 287857984
|
||||
pgscan_kswapd_movable 0
|
||||
pgscan_direct_dma 0
|
||||
pgscan_direct_dma32 12256
|
||||
pgscan_direct_normal 31501600
|
||||
pgscan_direct_movable 0
|
||||
zone_reclaim_failed 0
|
||||
pginodesteal 9188431
|
||||
slabs_scanned 93775616
|
||||
kswapd_steal 291534428
|
||||
kswapd_inodesteal 29770874
|
||||
kswapd_low_wmark_hit_quickly 8756
|
||||
kswapd_high_wmark_hit_quickly 25439
|
||||
kswapd_skip_congestion_wait 0
|
||||
pageoutrun 505006
|
||||
allocstall 81496
|
||||
pgrotated 60620
|
||||
compact_blocks_moved 238196
|
||||
compact_pages_moved 6370588
|
||||
compact_pagemigrate_failed 0
|
||||
compact_stall 142092
|
||||
compact_fail 135220
|
||||
compact_success 6872
|
||||
htlb_buddy_alloc_success 0
|
||||
htlb_buddy_alloc_fail 0
|
||||
unevictable_pgs_culled 1531
|
||||
unevictable_pgs_scanned 0
|
||||
unevictable_pgs_rescued 5426
|
||||
unevictable_pgs_mlocked 6988
|
||||
unevictable_pgs_munlocked 6988
|
||||
unevictable_pgs_cleared 0
|
||||
unevictable_pgs_stranded 0
|
||||
unevictable_pgs_mlockfreed 0
|
||||
thp_fault_alloc 346219
|
||||
thp_fault_fallback 895453
|
||||
thp_collapse_alloc 24857
|
||||
thp_collapse_alloc_failed 102214
|
||||
thp_split 9817`
|
||||
|
||||
const vmStatFile_Partial = `unevictable_pgs_culled 1531
|
||||
unevictable_pgs_scanned 0
|
||||
unevictable_pgs_rescued 5426
|
||||
unevictable_pgs_mlocked 6988
|
||||
unevictable_pgs_munlocked 6988
|
||||
unevictable_pgs_cleared 0
|
||||
unevictable_pgs_stranded 0
|
||||
unevictable_pgs_mlockfreed 0
|
||||
thp_fault_alloc 346219
|
||||
thp_fault_fallback 895453
|
||||
thp_collapse_alloc 24857
|
||||
thp_collapse_alloc_failed 102214
|
||||
thp_split 9817`
|
||||
|
||||
// invalid thp_split measurement
|
||||
const vmStatFile_Invalid = `unevictable_pgs_culled 1531
|
||||
unevictable_pgs_scanned 0
|
||||
unevictable_pgs_rescued 5426
|
||||
unevictable_pgs_mlocked 6988
|
||||
unevictable_pgs_munlocked 6988
|
||||
unevictable_pgs_cleared 0
|
||||
unevictable_pgs_stranded 0
|
||||
unevictable_pgs_mlockfreed 0
|
||||
thp_fault_alloc 346219
|
||||
thp_fault_fallback 895453
|
||||
thp_collapse_alloc 24857
|
||||
thp_collapse_alloc_failed 102214
|
||||
thp_split abcd`
|
||||
|
||||
func makeFakeVmStatFile(content []byte) string {
|
||||
tmpfile, err := ioutil.TempFile("", "kernel_vmstat_test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tmpfile.Name()
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"path"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
// https://www.kernel.org/doc/Documentation/sysctl/fs.txt
|
||||
type SysctlFS struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var sysctlFSDescription = `Provides Linux sysctl fs metrics`
|
||||
var sysctlFSSampleConfig = ``
|
||||
|
||||
func (_ SysctlFS) Description() string {
|
||||
return sysctlFSDescription
|
||||
}
|
||||
func (_ SysctlFS) SampleConfig() string {
|
||||
return sysctlFSSampleConfig
|
||||
}
|
||||
|
||||
func (sfs *SysctlFS) gatherList(file string, fields map[string]interface{}, fieldNames ...string) error {
|
||||
bs, err := ioutil.ReadFile(sfs.path + "/" + file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bsplit := bytes.Split(bytes.TrimRight(bs, "\n"), []byte{'\t'})
|
||||
for i, name := range fieldNames {
|
||||
if i >= len(bsplit) {
|
||||
break
|
||||
}
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := strconv.ParseUint(string(bsplit[i]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields[name] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sfs *SysctlFS) gatherOne(name string, fields map[string]interface{}) error {
|
||||
bs, err := ioutil.ReadFile(sfs.path + "/" + name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := strconv.ParseUint(string(bytes.TrimRight(bs, "\n")), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields[name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sfs *SysctlFS) Gather(acc telegraf.Accumulator) error {
|
||||
fields := map[string]interface{}{}
|
||||
|
||||
for _, n := range []string{"aio-nr", "aio-max-nr", "dquot-nr", "dquot-max", "super-nr", "super-max"} {
|
||||
sfs.gatherOne(n, fields)
|
||||
}
|
||||
|
||||
sfs.gatherList("inode-state", fields, "inode-nr", "inode-free-nr", "inode-preshrink-nr")
|
||||
sfs.gatherList("dentry-state", fields, "dentry-nr", "dentry-unused-nr", "dentry-age-limit", "dentry-want-pages")
|
||||
sfs.gatherList("file-nr", fields, "file-nr", "", "file-max")
|
||||
|
||||
acc.AddFields("linux_sysctl_fs", fields, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetHostProc() string {
|
||||
procPath := "/proc"
|
||||
if os.Getenv("HOST_PROC") != "" {
|
||||
procPath = os.Getenv("HOST_PROC")
|
||||
}
|
||||
return procPath
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
inputs.Add("linux_sysctl_fs", func() telegraf.Input {
|
||||
return &SysctlFS{
|
||||
path: path.Join(GetHostProc(), "/sys/fs"),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSysctlFSGather(t *testing.T) {
|
||||
td, err := ioutil.TempDir("", "")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
require.NoError(t, ioutil.WriteFile(td+"/aio-nr", []byte("100\n"), 0644))
|
||||
require.NoError(t, ioutil.WriteFile(td+"/aio-max-nr", []byte("101\n"), 0644))
|
||||
require.NoError(t, ioutil.WriteFile(td+"/super-nr", []byte("102\n"), 0644))
|
||||
require.NoError(t, ioutil.WriteFile(td+"/super-max", []byte("103\n"), 0644))
|
||||
require.NoError(t, ioutil.WriteFile(td+"/file-nr", []byte("104\t0\t106\n"), 0644))
|
||||
require.NoError(t, ioutil.WriteFile(td+"/inode-state", []byte("107\t108\t109\t0\t0\t0\t0\n"), 0644))
|
||||
|
||||
sfs := &SysctlFS{
|
||||
path: td,
|
||||
}
|
||||
var acc testutil.Accumulator
|
||||
require.NoError(t, sfs.Gather(&acc))
|
||||
|
||||
acc.AssertContainsFields(t, "linux_sysctl_fs", map[string]interface{}{
|
||||
"aio-nr": uint64(100),
|
||||
"aio-max-nr": uint64(101),
|
||||
"super-nr": uint64(102),
|
||||
"super-max": uint64(103),
|
||||
"file-nr": uint64(104),
|
||||
"file-max": uint64(106),
|
||||
"inode-nr": uint64(107),
|
||||
"inode-free-nr": uint64(108),
|
||||
"inode-preshrink-nr": uint64(109),
|
||||
})
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type MemStats struct {
|
||||
ps PS
|
||||
}
|
||||
|
||||
func (_ *MemStats) Description() string {
|
||||
return "Read metrics about memory usage"
|
||||
}
|
||||
|
||||
func (_ *MemStats) SampleConfig() string { return "" }
|
||||
|
||||
func (s *MemStats) Gather(acc telegraf.Accumulator) error {
|
||||
vm, err := s.ps.VMStat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting virtual memory info: %s", err)
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"total": vm.Total,
|
||||
"available": vm.Available,
|
||||
"used": vm.Used,
|
||||
"free": vm.Free,
|
||||
"cached": vm.Cached,
|
||||
"buffered": vm.Buffers,
|
||||
"active": vm.Active,
|
||||
"inactive": vm.Inactive,
|
||||
"wired": vm.Wired,
|
||||
"slab": vm.Slab,
|
||||
"used_percent": 100 * float64(vm.Used) / float64(vm.Total),
|
||||
"available_percent": 100 * float64(vm.Available) / float64(vm.Total),
|
||||
}
|
||||
acc.AddGauge("mem", fields, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
ps := newSystemPS()
|
||||
inputs.Add("mem", func() telegraf.Input {
|
||||
return &MemStats{ps: ps}
|
||||
})
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"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,
|
||||
Slab: 1234,
|
||||
Wired: 134,
|
||||
// Buffers: 771,
|
||||
// Cached: 4312,
|
||||
// Shared: 2142,
|
||||
}
|
||||
|
||||
mps.On("VMStat").Return(vms, nil)
|
||||
|
||||
err = (&MemStats{&mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
memfields := map[string]interface{}{
|
||||
"total": uint64(12400),
|
||||
"available": uint64(7600),
|
||||
"used": uint64(5000),
|
||||
"available_percent": float64(7600) / float64(12400) * 100,
|
||||
"used_percent": float64(5000) / float64(12400) * 100,
|
||||
"free": uint64(1235),
|
||||
"cached": uint64(0),
|
||||
"buffered": uint64(0),
|
||||
"active": uint64(8134),
|
||||
"inactive": uint64(1124),
|
||||
"wired": uint64(134),
|
||||
"slab": uint64(1234),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "mem", memfields, make(map[string]string))
|
||||
|
||||
acc.Metrics = nil
|
||||
}
|
||||
@@ -19,11 +19,11 @@ type MockPS struct {
|
||||
}
|
||||
|
||||
type MockPSDisk struct {
|
||||
*systemPS
|
||||
*SystemPS
|
||||
*mock.Mock
|
||||
}
|
||||
|
||||
type mockDiskUsage struct {
|
||||
type MockDiskUsage struct {
|
||||
*mock.Mock
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ func (m *MockPS) NetConnections() ([]net.ConnectionStat, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *mockDiskUsage) Partitions(all bool) ([]disk.PartitionStat, error) {
|
||||
func (m *MockDiskUsage) Partitions(all bool) ([]disk.PartitionStat, error) {
|
||||
ret := m.Called(all)
|
||||
|
||||
r0 := ret.Get(0).([]disk.PartitionStat)
|
||||
@@ -118,12 +118,12 @@ func (m *mockDiskUsage) Partitions(all bool) ([]disk.PartitionStat, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *mockDiskUsage) OSGetenv(key string) string {
|
||||
func (m *MockDiskUsage) OSGetenv(key string) string {
|
||||
ret := m.Called(key)
|
||||
return ret.Get(0).(string)
|
||||
}
|
||||
|
||||
func (m *mockDiskUsage) OSStat(name string) (os.FileInfo, error) {
|
||||
func (m *MockDiskUsage) OSStat(name string) (os.FileInfo, error) {
|
||||
ret := m.Called(name)
|
||||
|
||||
r0 := ret.Get(0).(os.FileInfo)
|
||||
@@ -132,7 +132,7 @@ func (m *mockDiskUsage) OSStat(name string) (os.FileInfo, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *mockDiskUsage) PSDiskUsage(path string) (*disk.UsageStat, error) {
|
||||
func (m *MockDiskUsage) PSDiskUsage(path string) (*disk.UsageStat, error) {
|
||||
ret := m.Called(path)
|
||||
|
||||
r0 := ret.Get(0).(*disk.UsageStat)
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type NetIOStats struct {
|
||||
filter filter.Filter
|
||||
ps PS
|
||||
|
||||
skipChecks bool
|
||||
IgnoreProtocolStats bool
|
||||
Interfaces []string
|
||||
}
|
||||
|
||||
func (_ *NetIOStats) Description() string {
|
||||
return "Read metrics about network interface usage"
|
||||
}
|
||||
|
||||
var netSampleConfig = `
|
||||
## By default, telegraf gathers stats from any up interface (excluding loopback)
|
||||
## Setting interfaces will tell it to gather these explicit interfaces,
|
||||
## regardless of status.
|
||||
##
|
||||
# interfaces = ["eth0"]
|
||||
##
|
||||
## On linux systems telegraf also collects protocol stats.
|
||||
## Setting ignore_protocol_stats to true will skip reporting of protocol metrics.
|
||||
##
|
||||
# ignore_protocol_stats = false
|
||||
##
|
||||
`
|
||||
|
||||
func (_ *NetIOStats) SampleConfig() string {
|
||||
return netSampleConfig
|
||||
}
|
||||
|
||||
func (s *NetIOStats) Gather(acc telegraf.Accumulator) error {
|
||||
netio, err := s.ps.NetIO()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting net io info: %s", err)
|
||||
}
|
||||
|
||||
if s.filter == nil {
|
||||
if s.filter, err = filter.Compile(s.Interfaces); err != nil {
|
||||
return fmt.Errorf("error compiling filter: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, io := range netio {
|
||||
if len(s.Interfaces) != 0 {
|
||||
var found bool
|
||||
|
||||
if s.filter.Match(io.Name) {
|
||||
found = true
|
||||
}
|
||||
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
} else if !s.skipChecks {
|
||||
iface, err := net.InterfaceByName(io.Name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if iface.Flags&net.FlagLoopback == net.FlagLoopback {
|
||||
continue
|
||||
}
|
||||
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"interface": io.Name,
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"bytes_sent": io.BytesSent,
|
||||
"bytes_recv": io.BytesRecv,
|
||||
"packets_sent": io.PacketsSent,
|
||||
"packets_recv": io.PacketsRecv,
|
||||
"err_in": io.Errin,
|
||||
"err_out": io.Errout,
|
||||
"drop_in": io.Dropin,
|
||||
"drop_out": io.Dropout,
|
||||
}
|
||||
acc.AddCounter("net", fields, tags)
|
||||
}
|
||||
|
||||
// Get system wide stats for different network protocols
|
||||
// (ignore these stats if the call fails)
|
||||
if !s.IgnoreProtocolStats {
|
||||
netprotos, _ := s.ps.NetProto()
|
||||
fields := make(map[string]interface{})
|
||||
for _, proto := range netprotos {
|
||||
for stat, value := range proto.Stats {
|
||||
name := fmt.Sprintf("%s_%s", strings.ToLower(proto.Protocol),
|
||||
strings.ToLower(stat))
|
||||
fields[name] = value
|
||||
}
|
||||
}
|
||||
tags := map[string]string{
|
||||
"interface": "all",
|
||||
}
|
||||
acc.AddFields("net", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("net", func() telegraf.Input {
|
||||
return &NetIOStats{ps: newSystemPS()}
|
||||
})
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
"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.IOCountersStat{
|
||||
Name: "eth0",
|
||||
BytesSent: 1123,
|
||||
BytesRecv: 8734422,
|
||||
PacketsSent: 781,
|
||||
PacketsRecv: 23456,
|
||||
Errin: 832,
|
||||
Errout: 8,
|
||||
Dropin: 7,
|
||||
Dropout: 1,
|
||||
}
|
||||
|
||||
mps.On("NetIO").Return([]net.IOCountersStat{netio}, nil)
|
||||
|
||||
netprotos := []net.ProtoCountersStat{
|
||||
net.ProtoCountersStat{
|
||||
Protocol: "Udp",
|
||||
Stats: map[string]int64{
|
||||
"InDatagrams": 4655,
|
||||
"NoPorts": 892592,
|
||||
},
|
||||
},
|
||||
}
|
||||
mps.On("NetProto").Return(netprotos, nil)
|
||||
|
||||
netstats := []net.ConnectionStat{
|
||||
net.ConnectionStat{
|
||||
Type: syscall.SOCK_DGRAM,
|
||||
},
|
||||
net.ConnectionStat{
|
||||
Status: "ESTABLISHED",
|
||||
},
|
||||
net.ConnectionStat{
|
||||
Status: "ESTABLISHED",
|
||||
},
|
||||
net.ConnectionStat{
|
||||
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",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"bytes_sent": uint64(1123),
|
||||
"bytes_recv": uint64(8734422),
|
||||
"packets_sent": uint64(781),
|
||||
"packets_recv": uint64(23456),
|
||||
"err_in": uint64(832),
|
||||
"err_out": uint64(8),
|
||||
"drop_in": uint64(7),
|
||||
"drop_out": uint64(1),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "net", fields1, ntags)
|
||||
|
||||
fields2 := map[string]interface{}{
|
||||
"udp_noports": int64(892592),
|
||||
"udp_indatagrams": int64(4655),
|
||||
}
|
||||
ntags = map[string]string{
|
||||
"interface": "all",
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "net", fields2, ntags)
|
||||
|
||||
acc.Metrics = nil
|
||||
|
||||
err = (&NetStats{&mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields3 := map[string]interface{}{
|
||||
"tcp_established": 2,
|
||||
"tcp_syn_sent": 0,
|
||||
"tcp_syn_recv": 0,
|
||||
"tcp_fin_wait1": 0,
|
||||
"tcp_fin_wait2": 0,
|
||||
"tcp_time_wait": 0,
|
||||
"tcp_close": 1,
|
||||
"tcp_close_wait": 0,
|
||||
"tcp_last_ack": 0,
|
||||
"tcp_listen": 0,
|
||||
"tcp_closing": 0,
|
||||
"tcp_none": 0,
|
||||
"udp_socket": 1,
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "netstat", fields3, make(map[string]string))
|
||||
|
||||
acc.Metrics = nil
|
||||
err = (&NetIOStats{ps: &mps, IgnoreProtocolStats: true}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
acc.AssertDoesNotContainsTaggedFields(t, "netstat", fields3, make(map[string]string))
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type NetStats struct {
|
||||
ps PS
|
||||
}
|
||||
|
||||
func (_ *NetStats) Description() string {
|
||||
return "Read TCP metrics such as established, time wait and sockets counts."
|
||||
}
|
||||
|
||||
var tcpstatSampleConfig = ""
|
||||
|
||||
func (_ *NetStats) SampleConfig() string {
|
||||
return tcpstatSampleConfig
|
||||
}
|
||||
|
||||
func (s *NetStats) Gather(acc telegraf.Accumulator) error {
|
||||
netconns, err := s.ps.NetConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting net connections info: %s", err)
|
||||
}
|
||||
counts := make(map[string]int)
|
||||
counts["UDP"] = 0
|
||||
|
||||
// TODO: add family to tags or else
|
||||
tags := map[string]string{}
|
||||
for _, netcon := range netconns {
|
||||
if netcon.Type == syscall.SOCK_DGRAM {
|
||||
counts["UDP"] += 1
|
||||
continue // UDP has no status
|
||||
}
|
||||
c, ok := counts[netcon.Status]
|
||||
if !ok {
|
||||
counts[netcon.Status] = 0
|
||||
}
|
||||
counts[netcon.Status] = c + 1
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"tcp_established": counts["ESTABLISHED"],
|
||||
"tcp_syn_sent": counts["SYN_SENT"],
|
||||
"tcp_syn_recv": counts["SYN_RECV"],
|
||||
"tcp_fin_wait1": counts["FIN_WAIT1"],
|
||||
"tcp_fin_wait2": counts["FIN_WAIT2"],
|
||||
"tcp_time_wait": counts["TIME_WAIT"],
|
||||
"tcp_close": counts["CLOSE"],
|
||||
"tcp_close_wait": counts["CLOSE_WAIT"],
|
||||
"tcp_last_ack": counts["LAST_ACK"],
|
||||
"tcp_listen": counts["LISTEN"],
|
||||
"tcp_closing": counts["CLOSING"],
|
||||
"tcp_none": counts["NONE"],
|
||||
"udp_socket": counts["UDP"],
|
||||
}
|
||||
acc.AddFields("netstat", fields, tags)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("netstat", func() telegraf.Input {
|
||||
return &NetStats{ps: newSystemPS()}
|
||||
})
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type Processes struct {
|
||||
execPS func() ([]byte, error)
|
||||
readProcFile func(filename string) ([]byte, error)
|
||||
|
||||
forcePS bool
|
||||
forceProc bool
|
||||
}
|
||||
|
||||
func (p *Processes) Description() string {
|
||||
return "Get the number of processes and group them by status"
|
||||
}
|
||||
|
||||
func (p *Processes) SampleConfig() string { return "" }
|
||||
|
||||
func (p *Processes) Gather(acc telegraf.Accumulator) error {
|
||||
// Get an empty map of metric fields
|
||||
fields := getEmptyFields()
|
||||
|
||||
// Decide if we will use 'ps' to get stats (use procfs otherwise)
|
||||
usePS := true
|
||||
if runtime.GOOS == "linux" {
|
||||
usePS = false
|
||||
}
|
||||
if p.forcePS {
|
||||
usePS = true
|
||||
} else if p.forceProc {
|
||||
usePS = false
|
||||
}
|
||||
|
||||
// Gather stats from 'ps' or procfs
|
||||
if usePS {
|
||||
if err := p.gatherFromPS(fields); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := p.gatherFromProc(fields); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddGauge("processes", fields, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gets empty fields of metrics based on the OS
|
||||
func getEmptyFields() map[string]interface{} {
|
||||
fields := map[string]interface{}{
|
||||
"blocked": int64(0),
|
||||
"zombies": int64(0),
|
||||
"stopped": int64(0),
|
||||
"running": int64(0),
|
||||
"sleeping": int64(0),
|
||||
"total": int64(0),
|
||||
"unknown": int64(0),
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
fields["idle"] = int64(0)
|
||||
fields["wait"] = int64(0)
|
||||
case "darwin":
|
||||
fields["idle"] = int64(0)
|
||||
case "openbsd":
|
||||
fields["idle"] = int64(0)
|
||||
case "linux":
|
||||
fields["dead"] = int64(0)
|
||||
fields["paging"] = int64(0)
|
||||
fields["total_threads"] = int64(0)
|
||||
fields["idle"] = int64(0)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// exec `ps` to get all process states
|
||||
func (p *Processes) gatherFromPS(fields map[string]interface{}) error {
|
||||
out, err := p.execPS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, status := range bytes.Fields(out) {
|
||||
if i == 0 && string(status) == "STAT" {
|
||||
// This is a header, skip it
|
||||
continue
|
||||
}
|
||||
switch status[0] {
|
||||
case 'W':
|
||||
fields["wait"] = fields["wait"].(int64) + int64(1)
|
||||
case 'U', 'D', 'L':
|
||||
// Also known as uninterruptible sleep or disk sleep
|
||||
fields["blocked"] = fields["blocked"].(int64) + int64(1)
|
||||
case 'Z':
|
||||
fields["zombies"] = fields["zombies"].(int64) + int64(1)
|
||||
case 'X':
|
||||
fields["dead"] = fields["dead"].(int64) + int64(1)
|
||||
case 'T':
|
||||
fields["stopped"] = fields["stopped"].(int64) + int64(1)
|
||||
case 'R':
|
||||
fields["running"] = fields["running"].(int64) + int64(1)
|
||||
case 'S':
|
||||
fields["sleeping"] = fields["sleeping"].(int64) + int64(1)
|
||||
case 'I':
|
||||
fields["idle"] = fields["idle"].(int64) + int64(1)
|
||||
case '?':
|
||||
fields["unknown"] = fields["unknown"].(int64) + int64(1)
|
||||
default:
|
||||
log.Printf("I! processes: Unknown state [ %s ] from ps",
|
||||
string(status[0]))
|
||||
}
|
||||
fields["total"] = fields["total"].(int64) + int64(1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// get process states from /proc/(pid)/stat files
|
||||
func (p *Processes) gatherFromProc(fields map[string]interface{}) error {
|
||||
filenames, err := filepath.Glob(GetHostProc() + "/[0-9]*/stat")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, filename := range filenames {
|
||||
_, err := os.Stat(filename)
|
||||
data, err := p.readProcFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse out data after (<cmd name>)
|
||||
i := bytes.LastIndex(data, []byte(")"))
|
||||
if i == -1 {
|
||||
continue
|
||||
}
|
||||
data = data[i+2:]
|
||||
|
||||
stats := bytes.Fields(data)
|
||||
if len(stats) < 3 {
|
||||
return fmt.Errorf("Something is terribly wrong with %s", filename)
|
||||
}
|
||||
switch stats[0][0] {
|
||||
case 'R':
|
||||
fields["running"] = fields["running"].(int64) + int64(1)
|
||||
case 'S':
|
||||
fields["sleeping"] = fields["sleeping"].(int64) + int64(1)
|
||||
case 'D':
|
||||
fields["blocked"] = fields["blocked"].(int64) + int64(1)
|
||||
case 'Z':
|
||||
fields["zombies"] = fields["zombies"].(int64) + int64(1)
|
||||
case 'X':
|
||||
fields["dead"] = fields["dead"].(int64) + int64(1)
|
||||
case 'T', 't':
|
||||
fields["stopped"] = fields["stopped"].(int64) + int64(1)
|
||||
case 'W':
|
||||
fields["paging"] = fields["paging"].(int64) + int64(1)
|
||||
case 'I':
|
||||
fields["idle"] = fields["idle"].(int64) + int64(1)
|
||||
default:
|
||||
log.Printf("I! processes: Unknown state [ %s ] in file %s",
|
||||
string(stats[0][0]), filename)
|
||||
}
|
||||
fields["total"] = fields["total"].(int64) + int64(1)
|
||||
|
||||
threads, err := strconv.Atoi(string(stats[17]))
|
||||
if err != nil {
|
||||
log.Printf("I! processes: Error parsing thread count: %s", err)
|
||||
continue
|
||||
}
|
||||
fields["total_threads"] = fields["total_threads"].(int64) + int64(threads)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readProcFile(filename string) ([]byte, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Reading from /proc/<PID> fails with ESRCH if the process has
|
||||
// been terminated between open() and read().
|
||||
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ESRCH {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func execPS() ([]byte, error) {
|
||||
bin, err := exec.LookPath("ps")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := exec.Command(bin, "axo", "state").Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return out, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("processes", func() telegraf.Input {
|
||||
return &Processes{
|
||||
execPS: execPS,
|
||||
readProcFile: readProcFile,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProcesses(t *testing.T) {
|
||||
processes := &Processes{
|
||||
execPS: execPS,
|
||||
readProcFile: readProcFile,
|
||||
}
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := processes.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, acc.HasInt64Field("processes", "running"))
|
||||
assert.True(t, acc.HasInt64Field("processes", "sleeping"))
|
||||
assert.True(t, acc.HasInt64Field("processes", "stopped"))
|
||||
assert.True(t, acc.HasInt64Field("processes", "total"))
|
||||
total, ok := acc.Get("processes")
|
||||
require.True(t, ok)
|
||||
assert.True(t, total.Fields["total"].(int64) > 0)
|
||||
}
|
||||
|
||||
func TestFromPS(t *testing.T) {
|
||||
processes := &Processes{
|
||||
execPS: testExecPS,
|
||||
forcePS: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := processes.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields := getEmptyFields()
|
||||
fields["blocked"] = int64(4)
|
||||
fields["zombies"] = int64(1)
|
||||
fields["running"] = int64(4)
|
||||
fields["sleeping"] = int64(34)
|
||||
fields["idle"] = int64(2)
|
||||
fields["total"] = int64(45)
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "processes", fields, map[string]string{})
|
||||
}
|
||||
|
||||
func TestFromPSError(t *testing.T) {
|
||||
processes := &Processes{
|
||||
execPS: testExecPSError,
|
||||
forcePS: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := processes.Gather(&acc)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFromProcFiles(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("This test only runs on linux")
|
||||
}
|
||||
tester := tester{}
|
||||
processes := &Processes{
|
||||
readProcFile: tester.testProcFile,
|
||||
forceProc: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := processes.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields := getEmptyFields()
|
||||
fields["sleeping"] = tester.calls
|
||||
fields["total_threads"] = tester.calls * 2
|
||||
fields["total"] = tester.calls
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "processes", fields, map[string]string{})
|
||||
}
|
||||
|
||||
func TestFromProcFilesWithSpaceInCmd(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("This test only runs on linux")
|
||||
}
|
||||
tester := tester{}
|
||||
processes := &Processes{
|
||||
readProcFile: tester.testProcFile2,
|
||||
forceProc: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := processes.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields := getEmptyFields()
|
||||
fields["sleeping"] = tester.calls
|
||||
fields["total_threads"] = tester.calls * 2
|
||||
fields["total"] = tester.calls
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "processes", fields, map[string]string{})
|
||||
}
|
||||
|
||||
func testExecPS() ([]byte, error) {
|
||||
return []byte(testPSOut), nil
|
||||
}
|
||||
|
||||
// struct for counting calls to testProcFile
|
||||
type tester struct {
|
||||
calls int64
|
||||
}
|
||||
|
||||
func (t *tester) testProcFile(_ string) ([]byte, error) {
|
||||
t.calls++
|
||||
return []byte(fmt.Sprintf(testProcStat, "S", "2")), nil
|
||||
}
|
||||
|
||||
func (t *tester) testProcFile2(_ string) ([]byte, error) {
|
||||
t.calls++
|
||||
return []byte(fmt.Sprintf(testProcStat2, "S", "2")), nil
|
||||
}
|
||||
|
||||
func testExecPSError() ([]byte, error) {
|
||||
return []byte(testPSOut), fmt.Errorf("ERROR!")
|
||||
}
|
||||
|
||||
const testPSOut = `
|
||||
STAT
|
||||
S
|
||||
S
|
||||
S
|
||||
S
|
||||
R
|
||||
R
|
||||
S
|
||||
S
|
||||
Ss
|
||||
Ss
|
||||
S
|
||||
SNs
|
||||
Ss
|
||||
Ss
|
||||
S
|
||||
R+
|
||||
S
|
||||
U
|
||||
S
|
||||
S
|
||||
S
|
||||
S
|
||||
Ss
|
||||
S+
|
||||
Ss
|
||||
S
|
||||
S+
|
||||
S+
|
||||
Ss
|
||||
S+
|
||||
Ss
|
||||
S
|
||||
R+
|
||||
Ss
|
||||
S
|
||||
S+
|
||||
S+
|
||||
Ss
|
||||
L
|
||||
U
|
||||
Z
|
||||
D
|
||||
S+
|
||||
I
|
||||
I
|
||||
`
|
||||
|
||||
const testProcStat = `10 (rcuob/0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
`
|
||||
|
||||
const testProcStat2 = `10 (rcuob 0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
`
|
||||
@@ -39,17 +39,17 @@ func add(acc telegraf.Accumulator,
|
||||
}
|
||||
}
|
||||
|
||||
func newSystemPS() *systemPS {
|
||||
return &systemPS{&systemPSDisk{}}
|
||||
func NewSystemPS() *SystemPS {
|
||||
return &SystemPS{&SystemPSDisk{}}
|
||||
}
|
||||
|
||||
type systemPS struct {
|
||||
type SystemPS struct {
|
||||
PSDiskDeps
|
||||
}
|
||||
|
||||
type systemPSDisk struct{}
|
||||
type SystemPSDisk struct{}
|
||||
|
||||
func (s *systemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error) {
|
||||
func (s *SystemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error) {
|
||||
var cpuTimes []cpu.TimesStat
|
||||
if perCPU {
|
||||
if perCPUTimes, err := cpu.Times(true); err == nil {
|
||||
@@ -68,7 +68,7 @@ func (s *systemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error) {
|
||||
return cpuTimes, nil
|
||||
}
|
||||
|
||||
func (s *systemPS) DiskUsage(
|
||||
func (s *SystemPS) DiskUsage(
|
||||
mountPointFilter []string,
|
||||
fstypeExclude []string,
|
||||
) ([]*disk.UsageStat, []*disk.PartitionStat, error) {
|
||||
@@ -139,19 +139,19 @@ func (s *systemPS) DiskUsage(
|
||||
return usage, partitions, nil
|
||||
}
|
||||
|
||||
func (s *systemPS) NetProto() ([]net.ProtoCountersStat, error) {
|
||||
func (s *SystemPS) NetProto() ([]net.ProtoCountersStat, error) {
|
||||
return net.ProtoCounters(nil)
|
||||
}
|
||||
|
||||
func (s *systemPS) NetIO() ([]net.IOCountersStat, error) {
|
||||
func (s *SystemPS) NetIO() ([]net.IOCountersStat, error) {
|
||||
return net.IOCounters(true)
|
||||
}
|
||||
|
||||
func (s *systemPS) NetConnections() ([]net.ConnectionStat, error) {
|
||||
func (s *SystemPS) NetConnections() ([]net.ConnectionStat, error) {
|
||||
return net.Connections("all")
|
||||
}
|
||||
|
||||
func (s *systemPS) DiskIO(names []string) (map[string]disk.IOCountersStat, error) {
|
||||
func (s *SystemPS) DiskIO(names []string) (map[string]disk.IOCountersStat, error) {
|
||||
m, err := disk.IOCounters(names...)
|
||||
if err == internal.NotImplementedError {
|
||||
return nil, nil
|
||||
@@ -160,26 +160,26 @@ func (s *systemPS) DiskIO(names []string) (map[string]disk.IOCountersStat, error
|
||||
return m, err
|
||||
}
|
||||
|
||||
func (s *systemPS) VMStat() (*mem.VirtualMemoryStat, error) {
|
||||
func (s *SystemPS) VMStat() (*mem.VirtualMemoryStat, error) {
|
||||
return mem.VirtualMemory()
|
||||
}
|
||||
|
||||
func (s *systemPS) SwapStat() (*mem.SwapMemoryStat, error) {
|
||||
func (s *SystemPS) SwapStat() (*mem.SwapMemoryStat, error) {
|
||||
return mem.SwapMemory()
|
||||
}
|
||||
|
||||
func (s *systemPSDisk) Partitions(all bool) ([]disk.PartitionStat, error) {
|
||||
func (s *SystemPSDisk) Partitions(all bool) ([]disk.PartitionStat, error) {
|
||||
return disk.Partitions(all)
|
||||
}
|
||||
|
||||
func (s *systemPSDisk) OSGetenv(key string) string {
|
||||
func (s *SystemPSDisk) OSGetenv(key string) string {
|
||||
return os.Getenv(key)
|
||||
}
|
||||
|
||||
func (s *systemPSDisk) OSStat(name string) (os.FileInfo, error) {
|
||||
func (s *SystemPSDisk) OSStat(name string) (os.FileInfo, error) {
|
||||
return os.Stat(name)
|
||||
}
|
||||
|
||||
func (s *systemPSDisk) PSDiskUsage(path string) (*disk.UsageStat, error) {
|
||||
func (s *SystemPSDisk) PSDiskUsage(path string) (*disk.UsageStat, error) {
|
||||
return disk.Usage(path)
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type SwapStats struct {
|
||||
ps PS
|
||||
}
|
||||
|
||||
func (_ *SwapStats) Description() string {
|
||||
return "Read metrics about swap memory usage"
|
||||
}
|
||||
|
||||
func (_ *SwapStats) SampleConfig() string { return "" }
|
||||
|
||||
func (s *SwapStats) Gather(acc telegraf.Accumulator) error {
|
||||
swap, err := s.ps.SwapStat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting swap memory info: %s", err)
|
||||
}
|
||||
|
||||
fieldsG := map[string]interface{}{
|
||||
"total": swap.Total,
|
||||
"used": swap.Used,
|
||||
"free": swap.Free,
|
||||
"used_percent": swap.UsedPercent,
|
||||
}
|
||||
fieldsC := map[string]interface{}{
|
||||
"in": swap.Sin,
|
||||
"out": swap.Sout,
|
||||
}
|
||||
acc.AddGauge("swap", fieldsG, nil)
|
||||
acc.AddCounter("swap", fieldsC, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
ps := newSystemPS()
|
||||
inputs.Add("swap", func() telegraf.Input {
|
||||
return &SwapStats{ps: ps}
|
||||
})
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSwapStats(t *testing.T) {
|
||||
var mps MockPS
|
||||
var err error
|
||||
defer mps.AssertExpectations(t)
|
||||
var acc testutil.Accumulator
|
||||
|
||||
sms := &mem.SwapMemoryStat{
|
||||
Total: 8123,
|
||||
Used: 1232,
|
||||
Free: 6412,
|
||||
UsedPercent: 12.2,
|
||||
Sin: 7,
|
||||
Sout: 830,
|
||||
}
|
||||
|
||||
mps.On("SwapStat").Return(sms, nil)
|
||||
|
||||
err = (&SwapStats{&mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
swapfields := map[string]interface{}{
|
||||
"total": uint64(8123),
|
||||
"used": uint64(1232),
|
||||
"used_percent": float64(12.2),
|
||||
"free": uint64(6412),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "swap", swapfields, make(map[string]string))
|
||||
}
|
||||
Reference in New Issue
Block a user