├── .gitignore ├── plugins ├── system │ ├── ps │ │ ├── doc.go │ │ ├── .gitignore │ │ ├── process │ │ │ ├── process_linux_386.go │ │ │ ├── process_linux_arm.go │ │ │ ├── process_linux_amd64.go │ │ │ ├── process_posix_test.go │ │ │ ├── process_posix.go │ │ │ ├── process_freebsd_386.go │ │ │ ├── process_freebsd_amd64.go │ │ │ ├── process.go │ │ │ ├── types_darwin.go │ │ │ └── process_darwin_amd64.go │ │ ├── load │ │ │ ├── load_windows.go │ │ │ ├── load.go │ │ │ ├── load_test.go │ │ │ ├── load_darwin.go │ │ │ ├── load_freebsd.go │ │ │ └── load_linux.go │ │ ├── host │ │ │ ├── types_darwin.go │ │ │ ├── host_darwin_amd64.go │ │ │ ├── host_freebsd_amd64.go │ │ │ ├── types_freebsd.go │ │ │ ├── types_linux.go │ │ │ ├── host_linux_386.go │ │ │ ├── host_linux_arm.go │ │ │ ├── host_linux_amd64.go │ │ │ ├── host.go │ │ │ ├── host_windows.go │ │ │ ├── host_test.go │ │ │ ├── host_linux_test.go │ │ │ ├── host_darwin.go │ │ │ └── host_freebsd.go │ │ ├── coverall.sh │ │ ├── mktypes.sh │ │ ├── windows_memo.rst │ │ ├── disk │ │ │ ├── disk_unix.go │ │ │ ├── disk.go │ │ │ ├── disk_darwin_amd64.go │ │ │ ├── disk_darwin.go │ │ │ ├── types_freebsd.go │ │ │ ├── disk_freebsd_amd64.go │ │ │ ├── disk_test.go │ │ │ ├── disk_linux.go │ │ │ └── disk_freebsd.go │ │ ├── mem │ │ │ ├── mem.go │ │ │ ├── mem_windows.go │ │ │ ├── mem_test.go │ │ │ ├── mem_linux.go │ │ │ ├── mem_darwin.go │ │ │ └── mem_freebsd.go │ │ ├── docker │ │ │ ├── docker_linux_test.go │ │ │ ├── docker_notlinux.go │ │ │ ├── docker.go │ │ │ └── docker_linux.go │ │ ├── common │ │ │ ├── common_darwin.go │ │ │ ├── common_freebsd.go │ │ │ ├── common_test.go │ │ │ ├── common.go │ │ │ └── common_windows.go │ │ ├── cpu │ │ │ ├── cpu_unix.go │ │ │ ├── cpu.go │ │ │ ├── cpu_test.go │ │ │ ├── cpu_windows.go │ │ │ ├── cpu_freebsd.go │ │ │ └── cpu_linux.go │ │ ├── LICENSE │ │ └── net │ │ │ ├── net_darwin.go │ │ │ ├── net_freebsd.go │ │ │ ├── net_linux.go │ │ │ ├── net_windows.go │ │ │ ├── net_test.go │ │ │ └── net.go │ ├── system.go │ ├── cpu.go │ ├── mock_PS.go │ ├── memory.go │ ├── net.go │ ├── disk.go │ ├── docker.go │ └── ps.go ├── mock_Plugin.go ├── all │ └── all.go ├── memcached │ ├── memcached_test.go │ └── memcached.go ├── kafka_consumer │ ├── README.md │ ├── kafka_consumer_integration_test.go │ ├── kafka_consumer_test.go │ └── kafka_consumer.go ├── registry.go ├── rethinkdb │ ├── rethinkdb_test.go │ ├── rethinkdb_server_test.go │ ├── rethinkdb.go │ ├── rethinkdb_data_test.go │ └── rethinkdb_data.go ├── mysql │ ├── mysql_test.go │ └── mysql.go ├── prometheus │ ├── prometheus_test.go │ └── prometheus.go └── postgresql │ ├── postgresql_test.go │ └── postgresql.go ├── testdata └── influx.toml ├── release.sh ├── LICENSE ├── agent_test.go ├── CHANGELOG.md ├── accumulator.go ├── cmd └── telegraf │ └── telegraf.go ├── testutil └── accumulator.go └── etc └── config.sample.toml /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/ 2 | tivan 3 | .vagrant 4 | -------------------------------------------------------------------------------- /plugins/system/ps/doc.go: -------------------------------------------------------------------------------- 1 | package gopsutil 2 | -------------------------------------------------------------------------------- /plugins/system/ps/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #* 3 | _obj 4 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_linux_386.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build 386 3 | 4 | package process 5 | 6 | const ( 7 | ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK) 8 | PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE) 9 | ) 10 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_linux_arm.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build arm 3 | 4 | package process 5 | 6 | const ( 7 | ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK) 8 | PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE) 9 | ) 10 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_linux_amd64.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build amd64 3 | 4 | package process 5 | 6 | const ( 7 | ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK) 8 | PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE) 9 | ) 10 | -------------------------------------------------------------------------------- /testdata/influx.toml: -------------------------------------------------------------------------------- 1 | [agent] 2 | interval = "5s" 3 | http = ":11213" 4 | debug = true 5 | 6 | [influxdb] 7 | url = "http://localhost:8086" 8 | username = "root" 9 | password = "root" 10 | database = "telegraf" 11 | tags = { dc = "us-phx-1" } 12 | 13 | [redis] 14 | address = ":6379" 15 | -------------------------------------------------------------------------------- /plugins/mock_Plugin.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import "github.com/stretchr/testify/mock" 4 | 5 | type MockPlugin struct { 6 | mock.Mock 7 | } 8 | 9 | func (m *MockPlugin) Gather(_a0 Accumulator) error { 10 | ret := m.Called(_a0) 11 | 12 | r0 := ret.Error(0) 13 | 14 | return r0 15 | } 16 | -------------------------------------------------------------------------------- /plugins/system/ps/load/load_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package load 4 | 5 | import ( 6 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 7 | ) 8 | 9 | func LoadAvg() (*LoadAvgStat, error) { 10 | ret := LoadAvgStat{} 11 | 12 | return &ret, common.NotImplementedError 13 | } 14 | -------------------------------------------------------------------------------- /plugins/system/ps/host/types_darwin.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // plus hand editing about timeval 3 | 4 | /* 5 | Input to cgo -godefs. 6 | */ 7 | 8 | package host 9 | 10 | /* 11 | #include 12 | #include 13 | */ 14 | import "C" 15 | 16 | type Utmpx C.struct_utmpx 17 | type Timeval C.struct_timeval 18 | -------------------------------------------------------------------------------- /plugins/system/ps/load/load.go: -------------------------------------------------------------------------------- 1 | package load 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type LoadAvgStat struct { 8 | Load1 float64 `json:"load1"` 9 | Load5 float64 `json:"load5"` 10 | Load15 float64 `json:"load15"` 11 | } 12 | 13 | func (l LoadAvgStat) String() string { 14 | s, _ := json.Marshal(l) 15 | return string(s) 16 | } 17 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_posix_test.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd 2 | 3 | package process 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | "testing" 9 | ) 10 | 11 | func Test_SendSignal(t *testing.T) { 12 | checkPid := os.Getpid() 13 | 14 | p, _ := NewProcess(int32(checkPid)) 15 | err := p.SendSignal(syscall.SIGCONT) 16 | if err != nil { 17 | t.Errorf("send signal %v", err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION="0.9.b1" 4 | 5 | echo "Building Telegraf version $VERSION" 6 | 7 | mkdir -p pkg 8 | 9 | build() { 10 | echo -n "=> $1-$2: " 11 | GOOS=$1 GOARCH=$2 go build -o pkg/telegraf-$1-$2 -ldflags "-X main.Version $VERSION" ./cmd/telegraf/telegraf.go 12 | du -h pkg/telegraf-$1-$2 13 | } 14 | 15 | build "darwin" "amd64" 16 | build "linux" "amd64" 17 | build "linux" "386" 18 | build "linux" "arm" 19 | -------------------------------------------------------------------------------- /plugins/all/all.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | _ "github.com/influxdb/telegraf/plugins/kafka_consumer" 5 | _ "github.com/influxdb/telegraf/plugins/memcached" 6 | _ "github.com/influxdb/telegraf/plugins/mysql" 7 | _ "github.com/influxdb/telegraf/plugins/postgresql" 8 | _ "github.com/influxdb/telegraf/plugins/prometheus" 9 | _ "github.com/influxdb/telegraf/plugins/redis" 10 | _ "github.com/influxdb/telegraf/plugins/system" 11 | ) 12 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_darwin_amd64.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs types_darwin.go 3 | 4 | package host 5 | 6 | type Utmpx struct { 7 | User [256]int8 8 | Id [4]int8 9 | Line [32]int8 10 | Pid int32 11 | Type int16 12 | Pad_cgo_0 [6]byte 13 | Tv Timeval 14 | Host [256]int8 15 | Pad [16]uint32 16 | } 17 | type Timeval struct { 18 | Sec int32 19 | } 20 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_freebsd_amd64.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | // +build amd64 3 | // Created by cgo -godefs - DO NOT EDIT 4 | // cgo -godefs host/types_freebsd.go 5 | 6 | package host 7 | 8 | const ( 9 | sizeofPtr = 0x8 10 | sizeofShort = 0x2 11 | sizeofInt = 0x4 12 | sizeofLong = 0x8 13 | sizeofLongLong = 0x8 14 | ) 15 | 16 | type ( 17 | _C_short int16 18 | _C_int int32 19 | _C_long int64 20 | _C_long_long int64 21 | ) 22 | 23 | type Utmp struct { 24 | Line [8]int8 25 | Name [16]int8 26 | Host [16]int8 27 | Time int32 28 | } 29 | -------------------------------------------------------------------------------- /plugins/system/ps/load/load_test.go: -------------------------------------------------------------------------------- 1 | package load 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestLoad(t *testing.T) { 9 | v, err := LoadAvg() 10 | if err != nil { 11 | t.Errorf("error %v", err) 12 | } 13 | 14 | empty := &LoadAvgStat{} 15 | if v == empty { 16 | t.Errorf("error load: %v", v) 17 | } 18 | } 19 | 20 | func TestLoadAvgStat_String(t *testing.T) { 21 | v := LoadAvgStat{ 22 | Load1: 10.1, 23 | Load5: 20.1, 24 | Load15: 30.1, 25 | } 26 | e := `{"load1":10.1,"load5":20.1,"load15":30.1}` 27 | if e != fmt.Sprintf("%v", v) { 28 | t.Errorf("LoadAvgStat string is invalid: %v", v) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /plugins/memcached/memcached_test.go: -------------------------------------------------------------------------------- 1 | package memcached 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/influxdb/telegraf/testutil" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestMemcachedGeneratesMetrics(t *testing.T) { 12 | m := &Memcached{ 13 | Servers: []string{"localhost"}, 14 | } 15 | 16 | var acc testutil.Accumulator 17 | 18 | err := m.Gather(&acc) 19 | require.NoError(t, err) 20 | 21 | intMetrics := []string{"get_hits", "get_misses", "evictions", "limit_maxbytes", "bytes"} 22 | 23 | for _, metric := range intMetrics { 24 | assert.True(t, acc.HasIntValue(metric), metric) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugins/system/ps/coverall.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | # see http://www.songmu.jp/riji/entry/2015-01-15-goveralls-multi-package.html 4 | 5 | set -e 6 | # cleanup 7 | cleanup() { 8 | if [ $tmpprof != "" ] && [ -f $tmpprof ]; then 9 | rm -f $tmpprof 10 | fi 11 | exit 12 | } 13 | trap cleanup INT QUIT TERM EXIT 14 | 15 | # メインの処理 16 | prof=${1:-".profile.cov"} 17 | echo "mode: count" > $prof 18 | gopath1=$(echo $GOPATH | cut -d: -f1) 19 | for pkg in $(go list ./...); do 20 | tmpprof=$gopath1/src/$pkg/profile.tmp 21 | go test -covermode=count -coverprofile=$tmpprof $pkg 22 | if [ -f $tmpprof ]; then 23 | cat $tmpprof | tail -n +2 >> $prof 24 | rm $tmpprof 25 | fi 26 | done 27 | -------------------------------------------------------------------------------- /plugins/system/ps/host/types_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | /* 4 | Input to cgo -godefs. 5 | */ 6 | 7 | package host 8 | 9 | /* 10 | #define KERNEL 11 | #include 12 | #include 13 | 14 | enum { 15 | sizeofPtr = sizeof(void*), 16 | }; 17 | 18 | */ 19 | import "C" 20 | 21 | // Machine characteristics; for internal use. 22 | 23 | const ( 24 | sizeofPtr = C.sizeofPtr 25 | sizeofShort = C.sizeof_short 26 | sizeofInt = C.sizeof_int 27 | sizeofLong = C.sizeof_long 28 | sizeofLongLong = C.sizeof_longlong 29 | ) 30 | 31 | // Basic types 32 | 33 | type ( 34 | _C_short C.short 35 | _C_int C.int 36 | _C_long C.long 37 | _C_long_long C.longlong 38 | ) 39 | 40 | type Utmp C.struct_utmp 41 | -------------------------------------------------------------------------------- /plugins/system/ps/mktypes.sh: -------------------------------------------------------------------------------- 1 | 2 | DIRS="cpu disk docker host load mem net process" 3 | 4 | GOOS=`uname | tr '[:upper:]' '[:lower:]'` 5 | ARCH=`uname -m` 6 | 7 | case $ARCH in 8 | amd64) 9 | GOARCH="amd64" 10 | ;; 11 | x86_64) 12 | GOARCH="amd64" 13 | ;; 14 | i386) 15 | GOARCH="386" 16 | ;; 17 | i686) 18 | GOARCH="386" 19 | ;; 20 | arm) 21 | GOARCH="arm" 22 | ;; 23 | *) 24 | echo "unknown arch: $ARCH" 25 | exit 1 26 | esac 27 | 28 | for DIR in $DIRS 29 | do 30 | if [ -e ${DIR}/types_${GOOS}.go ]; then 31 | echo "// +build $GOOS" > ${DIR}/${DIR}_${GOOS}_${GOARCH}.go 32 | echo "// +build $GOARCH" >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go 33 | go tool cgo -godefs ${DIR}/types_${GOOS}.go >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go 34 | fi 35 | done 36 | 37 | 38 | -------------------------------------------------------------------------------- /plugins/system/ps/load/load_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package load 4 | 5 | import ( 6 | "strconv" 7 | 8 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 9 | ) 10 | 11 | func LoadAvg() (*LoadAvgStat, error) { 12 | values, err := common.DoSysctrl("vm.loadavg") 13 | if err != nil { 14 | return nil, err 15 | } 16 | 17 | load1, err := strconv.ParseFloat(values[0], 64) 18 | if err != nil { 19 | return nil, err 20 | } 21 | load5, err := strconv.ParseFloat(values[1], 64) 22 | if err != nil { 23 | return nil, err 24 | } 25 | load15, err := strconv.ParseFloat(values[2], 64) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | ret := &LoadAvgStat{ 31 | Load1: float64(load1), 32 | Load5: float64(load5), 33 | Load15: float64(load15), 34 | } 35 | 36 | return ret, nil 37 | } 38 | -------------------------------------------------------------------------------- /plugins/system/ps/load/load_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package load 4 | 5 | import ( 6 | "strconv" 7 | 8 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 9 | ) 10 | 11 | func LoadAvg() (*LoadAvgStat, error) { 12 | values, err := common.DoSysctrl("vm.loadavg") 13 | if err != nil { 14 | return nil, err 15 | } 16 | 17 | load1, err := strconv.ParseFloat(values[0], 64) 18 | if err != nil { 19 | return nil, err 20 | } 21 | load5, err := strconv.ParseFloat(values[1], 64) 22 | if err != nil { 23 | return nil, err 24 | } 25 | load15, err := strconv.ParseFloat(values[2], 64) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | ret := &LoadAvgStat{ 31 | Load1: float64(load1), 32 | Load5: float64(load5), 33 | Load15: float64(load15), 34 | } 35 | 36 | return ret, nil 37 | } 38 | -------------------------------------------------------------------------------- /plugins/system/ps/windows_memo.rst: -------------------------------------------------------------------------------- 1 | Windows memo 2 | ===================== 3 | 4 | Size 5 | ---------- 6 | 7 | DWORD 8 | 32-bit unsigned integer 9 | DWORDLONG 10 | 64-bit unsigned integer 11 | DWORD_PTR 12 | unsigned long type for pointer precision 13 | DWORD32 14 | 32-bit unsigned integer 15 | DWORD64 16 | 64-bit unsigned integer 17 | HALF_PTR 18 | _WIN64 = int, else short 19 | INT 20 | 32-bit signed integer 21 | INT_PTR 22 | _WIN64 = __int64 else int 23 | LONG 24 | 32-bit signed integer 25 | LONGLONG 26 | 64-bit signed integer 27 | LONG_PTR 28 | _WIN64 = __int64 else long 29 | SHORT 30 | 16-bit integer 31 | SIZE_T 32 | maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T; 33 | SSIZE_T 34 | signed version of SIZE_T. typedef LONG_PTR SSIZE_T; 35 | WORD 36 | 16-bit unsigned integer -------------------------------------------------------------------------------- /plugins/system/ps/load/load_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package load 4 | 5 | import ( 6 | "io/ioutil" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func LoadAvg() (*LoadAvgStat, error) { 12 | filename := "/proc/loadavg" 13 | line, err := ioutil.ReadFile(filename) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | values := strings.Fields(string(line)) 19 | 20 | load1, err := strconv.ParseFloat(values[0], 64) 21 | if err != nil { 22 | return nil, err 23 | } 24 | load5, err := strconv.ParseFloat(values[1], 64) 25 | if err != nil { 26 | return nil, err 27 | } 28 | load15, err := strconv.ParseFloat(values[2], 64) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | ret := &LoadAvgStat{ 34 | Load1: load1, 35 | Load5: load5, 36 | Load15: load15, 37 | } 38 | 39 | return ret, nil 40 | } 41 | -------------------------------------------------------------------------------- /plugins/system/ps/host/types_linux.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | /* 4 | Input to cgo -godefs. 5 | */ 6 | 7 | package host 8 | 9 | /* 10 | #define KERNEL 11 | #include 12 | #include 13 | 14 | enum { 15 | sizeofPtr = sizeof(void*), 16 | }; 17 | 18 | */ 19 | import "C" 20 | 21 | // Machine characteristics; for internal use. 22 | 23 | const ( 24 | sizeofPtr = C.sizeofPtr 25 | sizeofShort = C.sizeof_short 26 | sizeofInt = C.sizeof_int 27 | sizeofLong = C.sizeof_long 28 | sizeofLongLong = C.sizeof_longlong 29 | ) 30 | 31 | // Basic types 32 | 33 | type ( 34 | _C_short C.short 35 | _C_int C.int 36 | _C_long C.long 37 | _C_long_long C.longlong 38 | ) 39 | 40 | type utmp C.struct_utmp 41 | type exit_status C.struct_exit_status 42 | type UtTv struct { 43 | TvSec int32 44 | TvUsec int32 45 | } 46 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_unix.go: -------------------------------------------------------------------------------- 1 | // +build freebsd linux darwin 2 | 3 | package disk 4 | 5 | import "syscall" 6 | 7 | func DiskUsage(path string) (*DiskUsageStat, error) { 8 | stat := syscall.Statfs_t{} 9 | err := syscall.Statfs(path, &stat) 10 | if err != nil { 11 | return nil, err 12 | } 13 | 14 | bsize := stat.Bsize 15 | 16 | ret := &DiskUsageStat{ 17 | Path: path, 18 | Total: (uint64(stat.Blocks) * uint64(bsize)), 19 | Free: (uint64(stat.Bfree) * uint64(bsize)), 20 | InodesTotal: (uint64(stat.Files)), 21 | InodesFree: (uint64(stat.Ffree)), 22 | } 23 | 24 | ret.InodesUsed = (ret.InodesTotal - ret.InodesFree) 25 | ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0 26 | ret.Used = (ret.Total - ret.Free) 27 | ret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0 28 | 29 | return ret, nil 30 | } 31 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_linux_386.go: -------------------------------------------------------------------------------- 1 | // ATTENTION - FILE MANUAL FIXED AFTER CGO. 2 | // Fixed line: Tv _Ctype_struct_timeval -> Tv UtTv 3 | // Created by cgo -godefs, MANUAL FIXED 4 | // cgo -godefs types_linux.go 5 | 6 | package host 7 | 8 | const ( 9 | sizeofPtr = 0x4 10 | sizeofShort = 0x2 11 | sizeofInt = 0x4 12 | sizeofLong = 0x4 13 | sizeofLongLong = 0x8 14 | ) 15 | 16 | type ( 17 | _C_short int16 18 | _C_int int32 19 | _C_long int32 20 | _C_long_long int64 21 | ) 22 | 23 | type utmp struct { 24 | Type int16 25 | Pad_cgo_0 [2]byte 26 | Pid int32 27 | Line [32]int8 28 | Id [4]int8 29 | User [32]int8 30 | Host [256]int8 31 | Exit exit_status 32 | Session int32 33 | Tv UtTv 34 | Addr_v6 [4]int32 35 | X__unused [20]int8 36 | } 37 | type exit_status struct { 38 | Termination int16 39 | Exit int16 40 | } 41 | type UtTv struct { 42 | TvSec int32 43 | TvUsec int32 44 | } 45 | -------------------------------------------------------------------------------- /plugins/kafka_consumer/README.md: -------------------------------------------------------------------------------- 1 | # Kafka Consumer 2 | 3 | The [Kafka](http://kafka.apache.org/) consumer plugin polls a specified Kafka 4 | topic and adds messages to InfluxDB. The plugin assumes messages follow the 5 | line protocol. [Consumer Group](http://godoc.org/github.com/wvanbergen/kafka/consumergroup) 6 | is used to talk to the Kafka cluster so multiple instances of telegraf can read 7 | from the same topic in parallel. 8 | 9 | ## Testing 10 | 11 | Running integration tests requires running Zookeeper & Kafka. The following 12 | commands assume you're on OS X & using [boot2docker](http://boot2docker.io/). 13 | 14 | To start Kafka & Zookeeper: 15 | 16 | ``` 17 | docker run -d -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=`boot2docker ip` --env ADVERTISED_PORT=9092 spotify/kafka 18 | ``` 19 | 20 | To run tests: 21 | 22 | ``` 23 | ZOOKEEPER_PEERS=$(boot2docker ip):2181 KAFKA_PEERS=$(boot2docker ip):9092 go test 24 | ``` 25 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_linux_arm.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build arm 3 | 4 | package host 5 | 6 | type exitStatus struct { 7 | Etermination int16 // Process termination status. 8 | Eexit int16 // Process exit status. 9 | } 10 | type timeval struct { 11 | TvSec uint32 // Seconds. 12 | TvUsec uint32 // Microseconds. 13 | } 14 | 15 | type utmp struct { 16 | Type int16 // Type of login. 17 | Pid int32 // Process ID of login process. 18 | Line [32]byte // Devicename. 19 | ID [4]byte // Inittab ID. 20 | User [32]byte // Username. 21 | Host [256]byte // Hostname for remote login. 22 | Exit exitStatus // Exit status of a process marked 23 | Session int32 // Session ID, used for windowing. 24 | Tv timeval // Time entry was made. 25 | AddrV6 [16]byte // Internet address of remote host. 26 | Unused [20]byte // Reserved for future use. // original is 20 27 | } 28 | -------------------------------------------------------------------------------- /plugins/system/system.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import "github.com/influxdb/telegraf/plugins" 4 | 5 | type SystemStats struct { 6 | ps PS 7 | } 8 | 9 | func (_ *SystemStats) Description() string { 10 | return "Read metrics about system load" 11 | } 12 | 13 | func (_ *SystemStats) SampleConfig() string { return "" } 14 | 15 | func (s *SystemStats) add(acc plugins.Accumulator, 16 | name string, val float64, tags map[string]string) { 17 | if val >= 0 { 18 | acc.Add(name, val, tags) 19 | } 20 | } 21 | 22 | func (s *SystemStats) Gather(acc plugins.Accumulator) error { 23 | lv, err := s.ps.LoadAvg() 24 | if err != nil { 25 | return err 26 | } 27 | 28 | acc.Add("load1", lv.Load1, nil) 29 | acc.Add("load5", lv.Load5, nil) 30 | acc.Add("load15", lv.Load15, nil) 31 | 32 | return nil 33 | } 34 | 35 | func init() { 36 | plugins.Add("system", func() plugins.Plugin { 37 | return &SystemStats{ps: &systemPS{}} 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_linux_amd64.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs types_linux.go 3 | 4 | package host 5 | 6 | const ( 7 | sizeofPtr = 0x8 8 | sizeofShort = 0x2 9 | sizeofInt = 0x4 10 | sizeofLong = 0x8 11 | sizeofLongLong = 0x8 12 | ) 13 | 14 | type ( 15 | _C_short int16 16 | _C_int int32 17 | _C_long int64 18 | _C_long_long int64 19 | ) 20 | 21 | type utmp struct { 22 | Type int16 23 | Pad_cgo_0 [2]byte 24 | Pid int32 25 | Line [32]int8 26 | Id [4]int8 27 | User [32]int8 28 | Host [256]int8 29 | Exit exit_status 30 | Session int32 31 | Tv UtTv 32 | Addr_v6 [4]int32 33 | X__glibc_reserved [20]int8 34 | } 35 | type exit_status struct { 36 | Termination int16 37 | Exit int16 38 | } 39 | type UtTv struct { 40 | TvSec int32 41 | TvUsec int32 42 | } 43 | -------------------------------------------------------------------------------- /plugins/registry.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import "time" 4 | 5 | type Accumulator interface { 6 | // Create a point with a value, decorating it with tags 7 | // NOTE: tags is expected to be owned by the caller, don't mutate 8 | // it after passing to Add. 9 | Add(measurement string, value interface{}, tags map[string]string) 10 | 11 | // Create a point with a set of values, decorating it with tags 12 | // NOTE: tags and values are expected to be owned by the caller, don't mutate 13 | // them after passing to AddValuesWithTime. 14 | AddValuesWithTime( 15 | measurement string, 16 | values map[string]interface{}, 17 | tags map[string]string, 18 | timestamp time.Time, 19 | ) 20 | } 21 | 22 | type Plugin interface { 23 | SampleConfig() string 24 | Description() string 25 | Gather(Accumulator) error 26 | } 27 | 28 | type Creator func() Plugin 29 | 30 | var Plugins = map[string]Creator{} 31 | 32 | func Add(name string, creator Creator) { 33 | Plugins[name] = creator 34 | } 35 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem.go: -------------------------------------------------------------------------------- 1 | package mem 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type VirtualMemoryStat struct { 8 | Total uint64 `json:"total"` 9 | Available uint64 `json:"available"` 10 | Used uint64 `json:"used"` 11 | UsedPercent float64 `json:"used_percent"` 12 | Free uint64 `json:"free"` 13 | Active uint64 `json:"active"` 14 | Inactive uint64 `json:"inactive"` 15 | Buffers uint64 `json:"buffers"` 16 | Cached uint64 `json:"cached"` 17 | Wired uint64 `json:"wired"` 18 | Shared uint64 `json:"shared"` 19 | } 20 | 21 | type SwapMemoryStat struct { 22 | Total uint64 `json:"total"` 23 | Used uint64 `json:"used"` 24 | Free uint64 `json:"free"` 25 | UsedPercent float64 `json:"used_percent"` 26 | Sin uint64 `json:"sin"` 27 | Sout uint64 `json:"sout"` 28 | } 29 | 30 | func (m VirtualMemoryStat) String() string { 31 | s, _ := json.Marshal(m) 32 | return string(s) 33 | } 34 | 35 | func (m SwapMemoryStat) String() string { 36 | s, _ := json.Marshal(m) 37 | return string(s) 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 InfluxDB 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host.go: -------------------------------------------------------------------------------- 1 | package host 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // A HostInfoStat describes the host status. 8 | // This is not in the psutil but it useful. 9 | type HostInfoStat struct { 10 | Hostname string `json:"hostname"` 11 | Uptime uint64 `json:"uptime"` 12 | Procs uint64 `json:"procs"` // number of processes 13 | OS string `json:"os"` // ex: freebsd, linux 14 | Platform string `json:"platform"` // ex: ubuntu, linuxmint 15 | PlatformFamily string `json:"platform_family"` // ex: debian, rhel 16 | PlatformVersion string `json:"platform_version"` 17 | VirtualizationSystem string `json:"virtualization_system"` 18 | VirtualizationRole string `json:"virtualization_role"` // guest or host 19 | 20 | } 21 | 22 | type UserStat struct { 23 | User string `json:"user"` 24 | Terminal string `json:"terminal"` 25 | Host string `json:"host"` 26 | Started int `json:"started"` 27 | } 28 | 29 | func (h HostInfoStat) String() string { 30 | s, _ := json.Marshal(h) 31 | return string(s) 32 | } 33 | 34 | func (u UserStat) String() string { 35 | s, _ := json.Marshal(u) 36 | return string(s) 37 | } 38 | -------------------------------------------------------------------------------- /plugins/system/cpu.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/influxdb/telegraf/plugins" 7 | ) 8 | 9 | type CPUStats struct { 10 | ps PS 11 | } 12 | 13 | func (_ *CPUStats) Description() string { 14 | return "Read metrics about cpu usage" 15 | } 16 | 17 | func (_ *CPUStats) SampleConfig() string { return "" } 18 | 19 | func (s *CPUStats) Gather(acc plugins.Accumulator) error { 20 | times, err := s.ps.CPUTimes() 21 | if err != nil { 22 | return fmt.Errorf("error getting CPU info: %s", err) 23 | } 24 | 25 | for _, cts := range times { 26 | tags := map[string]string{ 27 | "cpu": cts.CPU, 28 | } 29 | 30 | add(acc, "user", cts.User, tags) 31 | add(acc, "system", cts.System, tags) 32 | add(acc, "idle", cts.Idle, tags) 33 | add(acc, "nice", cts.Nice, tags) 34 | add(acc, "iowait", cts.Iowait, tags) 35 | add(acc, "irq", cts.Irq, tags) 36 | add(acc, "softirq", cts.Softirq, tags) 37 | add(acc, "steal", cts.Steal, tags) 38 | add(acc, "guest", cts.Guest, tags) 39 | add(acc, "guestNice", cts.GuestNice, tags) 40 | add(acc, "stolen", cts.Stolen, tags) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func init() { 47 | plugins.Add("cpu", func() plugins.Plugin { 48 | return &CPUStats{ps: &systemPS{}} 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /plugins/rethinkdb/rethinkdb_test.go: -------------------------------------------------------------------------------- 1 | // +build integration 2 | 3 | package rethinkdb 4 | 5 | import ( 6 | "log" 7 | "math/rand" 8 | "net/url" 9 | "os" 10 | "testing" 11 | "time" 12 | 13 | "gopkg.in/dancannon/gorethink.v1" 14 | ) 15 | 16 | var connect_url, authKey string 17 | var server *Server 18 | 19 | func init() { 20 | connect_url = os.Getenv("RETHINKDB_URL") 21 | if connect_url == "" { 22 | connect_url = "127.0.0.1:28015" 23 | } 24 | authKey = os.Getenv("RETHINKDB_AUTHKEY") 25 | 26 | } 27 | 28 | func testSetup(m *testing.M) { 29 | var err error 30 | server = &Server{Url: &url.URL{Host: connect_url}} 31 | server.session, _ = gorethink.Connect(gorethink.ConnectOpts{ 32 | Address: server.Url.Host, 33 | AuthKey: authKey, 34 | DiscoverHosts: false, 35 | }) 36 | if err != nil { 37 | log.Fatalln(err.Error()) 38 | } 39 | 40 | err = server.getServerStatus() 41 | if err != nil { 42 | log.Fatalln(err.Error()) 43 | } 44 | } 45 | 46 | func testTeardown(m *testing.M) { 47 | server.session.Close() 48 | } 49 | 50 | func TestMain(m *testing.M) { 51 | // seed randomness for use with tests 52 | rand.Seed(time.Now().UTC().UnixNano()) 53 | 54 | testSetup(m) 55 | res := m.Run() 56 | testTeardown(m) 57 | 58 | os.Exit(res) 59 | } 60 | -------------------------------------------------------------------------------- /plugins/mysql/mysql_test.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/influxdb/telegraf/testutil" 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestMysqlGeneratesMetrics(t *testing.T) { 13 | m := &Mysql{ 14 | Servers: []string{""}, 15 | } 16 | 17 | var acc testutil.Accumulator 18 | 19 | err := m.Gather(&acc) 20 | require.NoError(t, err) 21 | 22 | prefixes := []struct { 23 | prefix string 24 | count int 25 | }{ 26 | {"commands", 141}, 27 | {"handler", 18}, 28 | {"bytes", 2}, 29 | {"innodb", 51}, 30 | {"threads", 4}, 31 | } 32 | 33 | intMetrics := []string{ 34 | "queries", 35 | "slow_queries", 36 | } 37 | 38 | for _, prefix := range prefixes { 39 | var count int 40 | 41 | for _, p := range acc.Points { 42 | if strings.HasPrefix(p.Measurement, prefix.prefix) { 43 | count++ 44 | } 45 | } 46 | 47 | assert.Equal(t, prefix.count, count) 48 | } 49 | 50 | for _, metric := range intMetrics { 51 | assert.True(t, acc.HasIntValue(metric)) 52 | } 53 | } 54 | 55 | func TestMysqlDefaultsToLocal(t *testing.T) { 56 | m := &Mysql{} 57 | 58 | var acc testutil.Accumulator 59 | 60 | err := m.Gather(&acc) 61 | require.NoError(t, err) 62 | 63 | assert.True(t, len(acc.Points) > 0) 64 | } 65 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package mem 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 10 | ) 11 | 12 | var ( 13 | procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx") 14 | ) 15 | 16 | type MEMORYSTATUSEX struct { 17 | cbSize uint32 18 | dwMemoryLoad uint32 19 | ullTotalPhys uint64 // in bytes 20 | ullAvailPhys uint64 21 | ullTotalPageFile uint64 22 | ullAvailPageFile uint64 23 | ullTotalVirtual uint64 24 | ullAvailVirtual uint64 25 | ullAvailExtendedVirtual uint64 26 | } 27 | 28 | func VirtualMemory() (*VirtualMemoryStat, error) { 29 | var memInfo MEMORYSTATUSEX 30 | memInfo.cbSize = uint32(unsafe.Sizeof(memInfo)) 31 | mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo))) 32 | if mem == 0 { 33 | return nil, syscall.GetLastError() 34 | } 35 | 36 | ret := &VirtualMemoryStat{ 37 | Total: memInfo.ullTotalPhys, 38 | Available: memInfo.ullAvailPhys, 39 | UsedPercent: float64(memInfo.dwMemoryLoad), 40 | } 41 | 42 | ret.Used = ret.Total - ret.Available 43 | return ret, nil 44 | } 45 | 46 | func SwapMemory() (*SwapMemoryStat, error) { 47 | ret := &SwapMemoryStat{} 48 | 49 | return ret, nil 50 | } 51 | -------------------------------------------------------------------------------- /agent_test.go: -------------------------------------------------------------------------------- 1 | package telegraf 2 | 3 | /* 4 | func TestAgent_DrivesMetrics(t *testing.T) { 5 | var ( 6 | plugin plugins.MockPlugin 7 | ) 8 | 9 | defer plugin.AssertExpectations(t) 10 | defer metrics.AssertExpectations(t) 11 | 12 | a := &Agent{ 13 | plugins: []plugins.Plugin{&plugin}, 14 | Config: &Config{}, 15 | } 16 | 17 | plugin.On("Add", "foo", 1.2, nil).Return(nil) 18 | plugin.On("Add", "bar", 888, nil).Return(nil) 19 | 20 | err := a.crank() 21 | require.NoError(t, err) 22 | } 23 | 24 | func TestAgent_AppliesTags(t *testing.T) { 25 | var ( 26 | plugin plugins.MockPlugin 27 | metrics MockMetrics 28 | ) 29 | 30 | defer plugin.AssertExpectations(t) 31 | defer metrics.AssertExpectations(t) 32 | 33 | a := &Agent{ 34 | plugins: []plugins.Plugin{&plugin}, 35 | metrics: &metrics, 36 | Config: &Config{ 37 | Tags: map[string]string{ 38 | "dc": "us-west-1", 39 | }, 40 | }, 41 | } 42 | 43 | m1 := cypress.Metric() 44 | m1.Add("name", "foo") 45 | m1.Add("value", 1.2) 46 | 47 | msgs := []*cypress.Message{m1} 48 | 49 | m2 := cypress.Metric() 50 | m2.Timestamp = m1.Timestamp 51 | m2.Add("name", "foo") 52 | m2.Add("value", 1.2) 53 | m2.AddTag("dc", "us-west-1") 54 | 55 | plugin.On("Read").Return(msgs, nil) 56 | metrics.On("Receive", m2).Return(nil) 57 | 58 | err := a.crank() 59 | require.NoError(t, err) 60 | } 61 | */ 62 | -------------------------------------------------------------------------------- /plugins/system/ps/docker/docker_linux_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package docker 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestGetDockerIDList(t *testing.T) { 10 | // If there is not docker environment, this test always fail. 11 | // not tested here 12 | /* 13 | _, err := GetDockerIDList() 14 | if err != nil { 15 | t.Errorf("error %v", err) 16 | } 17 | */ 18 | } 19 | 20 | func TestCgroupCPU(t *testing.T) { 21 | v, _ := GetDockerIDList() 22 | for _, id := range v { 23 | v, err := CgroupCPUDocker(id) 24 | if err != nil { 25 | t.Errorf("error %v", err) 26 | } 27 | if v.CPU == "" { 28 | t.Errorf("could not get CgroupCPU %v", v) 29 | } 30 | 31 | } 32 | } 33 | 34 | func TestCgroupCPUInvalidId(t *testing.T) { 35 | _, err := CgroupCPUDocker("bad id") 36 | if err == nil { 37 | t.Error("Expected path does not exist error") 38 | } 39 | } 40 | 41 | func TestCgroupMem(t *testing.T) { 42 | v, _ := GetDockerIDList() 43 | for _, id := range v { 44 | v, err := CgroupMemDocker(id) 45 | if err != nil { 46 | t.Errorf("error %v", err) 47 | } 48 | empty := &CgroupMemStat{} 49 | if v == empty { 50 | t.Errorf("Could not CgroupMemStat %v", v) 51 | } 52 | } 53 | } 54 | 55 | func TestCgroupMemInvalidId(t *testing.T) { 56 | _, err := CgroupMemDocker("bad id") 57 | if err == nil { 58 | t.Error("Expected path does not exist error") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /plugins/system/ps/docker/docker_notlinux.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package docker 4 | 5 | import ( 6 | "encoding/json" 7 | 8 | "github.com/influxdb/telegraf/plugins/system/ps/common" 9 | "github.com/influxdb/telegraf/plugins/system/ps/cpu" 10 | ) 11 | 12 | // GetDockerIDList returnes a list of DockerID. 13 | // This requires certain permission. 14 | func GetDockerIDList() ([]string, error) { 15 | return nil, common.NotImplementedError 16 | } 17 | 18 | // CgroupCPU returnes specified cgroup id CPU status. 19 | // containerid is same as docker id if you use docker. 20 | // If you use container via systemd.slice, you could use 21 | // containerid = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ 22 | func CgroupCPU(containerid string, base string) (*cpu.CPUTimesStat, error) { 23 | return nil, common.NotImplementedError 24 | } 25 | 26 | func CgroupCPUDocker(containerid string) (*cpu.CPUTimesStat, error) { 27 | return CgroupCPU(containerid, "/sys/fs/cgroup/cpuacct/docker") 28 | } 29 | 30 | func CgroupMem(containerid string, base string) (*CgroupMemStat, error) { 31 | return nil, common.NotImplementedError 32 | } 33 | 34 | func CgroupMemDocker(containerid string) (*CgroupMemStat, error) { 35 | return CgroupMem(containerid, "/sys/fs/cgroup/memory/docker") 36 | } 37 | 38 | func (m CgroupMemStat) String() string { 39 | s, _ := json.Marshal(m) 40 | return string(s) 41 | } 42 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem_test.go: -------------------------------------------------------------------------------- 1 | package mem 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestVirtual_memory(t *testing.T) { 9 | v, err := VirtualMemory() 10 | if err != nil { 11 | t.Errorf("error %v", err) 12 | } 13 | empty := &VirtualMemoryStat{} 14 | if v == empty { 15 | t.Errorf("error %v", v) 16 | } 17 | } 18 | 19 | func TestSwap_memory(t *testing.T) { 20 | v, err := SwapMemory() 21 | if err != nil { 22 | t.Errorf("error %v", err) 23 | } 24 | empty := &SwapMemoryStat{} 25 | if v == empty { 26 | t.Errorf("error %v", v) 27 | } 28 | } 29 | 30 | func TestVirtualMemoryStat_String(t *testing.T) { 31 | v := VirtualMemoryStat{ 32 | Total: 10, 33 | Available: 20, 34 | Used: 30, 35 | UsedPercent: 30.1, 36 | Free: 40, 37 | } 38 | e := `{"total":10,"available":20,"used":30,"used_percent":30.1,"free":40,"active":0,"inactive":0,"buffers":0,"cached":0,"wired":0,"shared":0}` 39 | if e != fmt.Sprintf("%v", v) { 40 | t.Errorf("VirtualMemoryStat string is invalid: %v", v) 41 | } 42 | } 43 | 44 | func TestSwapMemoryStat_String(t *testing.T) { 45 | v := SwapMemoryStat{ 46 | Total: 10, 47 | Used: 30, 48 | Free: 40, 49 | UsedPercent: 30.1, 50 | } 51 | e := `{"total":10,"used":30,"free":40,"used_percent":30.1,"sin":0,"sout":0}` 52 | if e != fmt.Sprintf("%v", v) { 53 | t.Errorf("SwapMemoryStat string is invalid: %v", v) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /plugins/system/ps/common/common_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package common 4 | 5 | import ( 6 | "os/exec" 7 | "strings" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | func DoSysctrl(mib string) ([]string, error) { 13 | out, err := exec.Command("/usr/sbin/sysctl", "-n", mib).Output() 14 | if err != nil { 15 | return []string{}, err 16 | } 17 | v := strings.Replace(string(out), "{ ", "", 1) 18 | v = strings.Replace(string(v), " }", "", 1) 19 | values := strings.Fields(string(v)) 20 | 21 | return values, nil 22 | } 23 | 24 | func CallSyscall(mib []int32) ([]byte, uint64, error) { 25 | miblen := uint64(len(mib)) 26 | 27 | // get required buffer size 28 | length := uint64(0) 29 | _, _, err := syscall.Syscall6( 30 | syscall.SYS___SYSCTL, 31 | uintptr(unsafe.Pointer(&mib[0])), 32 | uintptr(miblen), 33 | 0, 34 | uintptr(unsafe.Pointer(&length)), 35 | 0, 36 | 0) 37 | if err != 0 { 38 | var b []byte 39 | return b, length, err 40 | } 41 | if length == 0 { 42 | var b []byte 43 | return b, length, err 44 | } 45 | // get proc info itself 46 | buf := make([]byte, length) 47 | _, _, err = syscall.Syscall6( 48 | syscall.SYS___SYSCTL, 49 | uintptr(unsafe.Pointer(&mib[0])), 50 | uintptr(miblen), 51 | uintptr(unsafe.Pointer(&buf[0])), 52 | uintptr(unsafe.Pointer(&length)), 53 | 0, 54 | 0) 55 | if err != 0 { 56 | return buf, length, err 57 | } 58 | 59 | return buf, length, nil 60 | } 61 | -------------------------------------------------------------------------------- /plugins/system/ps/common/common_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package common 4 | 5 | import ( 6 | "syscall" 7 | "os/exec" 8 | "strings" 9 | "unsafe" 10 | ) 11 | 12 | func DoSysctrl(mib string) ([]string, error) { 13 | out, err := exec.Command("/sbin/sysctl", "-n", mib).Output() 14 | if err != nil { 15 | return []string{}, err 16 | } 17 | v := strings.Replace(string(out), "{ ", "", 1) 18 | v = strings.Replace(string(v), " }", "", 1) 19 | values := strings.Fields(string(v)) 20 | 21 | return values, nil 22 | } 23 | 24 | func CallSyscall(mib []int32) ([]byte, uint64, error) { 25 | miblen := uint64(len(mib)) 26 | 27 | // get required buffer size 28 | length := uint64(0) 29 | _, _, err := syscall.Syscall6( 30 | syscall.SYS___SYSCTL, 31 | uintptr(unsafe.Pointer(&mib[0])), 32 | uintptr(miblen), 33 | 0, 34 | uintptr(unsafe.Pointer(&length)), 35 | 0, 36 | 0) 37 | if err != 0 { 38 | var b []byte 39 | return b, length, err 40 | } 41 | if length == 0 { 42 | var b []byte 43 | return b, length, err 44 | } 45 | // get proc info itself 46 | buf := make([]byte, length) 47 | _, _, err = syscall.Syscall6( 48 | syscall.SYS___SYSCTL, 49 | uintptr(unsafe.Pointer(&mib[0])), 50 | uintptr(miblen), 51 | uintptr(unsafe.Pointer(&buf[0])), 52 | uintptr(unsafe.Pointer(&length)), 53 | 0, 54 | 0) 55 | if err != 0 { 56 | return buf, length, err 57 | } 58 | 59 | return buf, length, nil 60 | } 61 | 62 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package host 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "strings" 9 | "time" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | process "github.com/influxdb/telegraf/plugins/system/ps/process" 13 | ) 14 | 15 | var ( 16 | procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime") 17 | ) 18 | 19 | func HostInfo() (*HostInfoStat, error) { 20 | ret := &HostInfoStat{} 21 | hostname, err := os.Hostname() 22 | if err != nil { 23 | return ret, err 24 | } 25 | 26 | ret.Hostname = hostname 27 | uptime, err := BootTime() 28 | if err == nil { 29 | ret.Uptime = uptime 30 | } 31 | 32 | procs, err := process.Pids() 33 | if err != nil { 34 | return ret, err 35 | } 36 | 37 | ret.Procs = uint64(len(procs)) 38 | 39 | return ret, nil 40 | } 41 | 42 | func BootTime() (uint64, error) { 43 | lines, err := common.GetWmic("os", "get", "LastBootUpTime") 44 | if err != nil { 45 | return 0, err 46 | } 47 | if len(lines) == 0 || len(lines[0]) != 2 { 48 | return 0, fmt.Errorf("could not get LastBootUpTime") 49 | } 50 | format := "20060102150405" 51 | t, err := time.Parse(format, strings.Split(lines[0][1], ".")[0]) 52 | if err != nil { 53 | return 0, err 54 | } 55 | now := time.Now() 56 | return uint64(now.Sub(t).Seconds()), nil 57 | } 58 | 59 | func Users() ([]UserStat, error) { 60 | 61 | var ret []UserStat 62 | 63 | return ret, nil 64 | } 65 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd darwin 2 | 3 | package cpu 4 | 5 | import "time" 6 | 7 | func init() { 8 | lastCPUTimes, _ = CPUTimes(false) 9 | lastPerCPUTimes, _ = CPUTimes(true) 10 | } 11 | 12 | func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) { 13 | getAllBusy := func(t CPUTimesStat) (float64, float64) { 14 | busy := t.User + t.System + t.Nice + t.Iowait + t.Irq + 15 | t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen 16 | return busy + t.Idle, busy 17 | } 18 | 19 | calculate := func(t1, t2 CPUTimesStat) float64 { 20 | t1All, t1Busy := getAllBusy(t1) 21 | t2All, t2Busy := getAllBusy(t2) 22 | 23 | if t2Busy <= t1Busy { 24 | return 0 25 | } 26 | if t2All <= t1All { 27 | return 1 28 | } 29 | return (t2Busy - t1Busy) / (t2All - t1All) * 100 30 | } 31 | 32 | cpuTimes, err := CPUTimes(percpu) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | if interval > 0 { 38 | if !percpu { 39 | lastCPUTimes = cpuTimes 40 | } else { 41 | lastPerCPUTimes = cpuTimes 42 | } 43 | time.Sleep(interval) 44 | cpuTimes, err = CPUTimes(percpu) 45 | if err != nil { 46 | return nil, err 47 | } 48 | } 49 | 50 | ret := make([]float64, len(cpuTimes)) 51 | if !percpu { 52 | ret[0] = calculate(lastCPUTimes[0], cpuTimes[0]) 53 | lastCPUTimes = cpuTimes 54 | } else { 55 | for i, t := range cpuTimes { 56 | ret[i] = calculate(lastPerCPUTimes[i], t) 57 | } 58 | lastPerCPUTimes = cpuTimes 59 | } 60 | return ret, nil 61 | } 62 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk.go: -------------------------------------------------------------------------------- 1 | package disk 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type DiskUsageStat struct { 8 | Path string `json:"path"` 9 | Total uint64 `json:"total"` 10 | Free uint64 `json:"free"` 11 | Used uint64 `json:"used"` 12 | UsedPercent float64 `json:"used_percent"` 13 | InodesTotal uint64 `json:"inodes_total"` 14 | InodesUsed uint64 `json:"inodes_used"` 15 | InodesFree uint64 `json:"inodes_free"` 16 | InodesUsedPercent float64 `json:"inodes_used_percent"` 17 | } 18 | 19 | type DiskPartitionStat struct { 20 | Device string `json:"device"` 21 | Mountpoint string `json:"mountpoint"` 22 | Fstype string `json:"fstype"` 23 | Opts string `json:"opts"` 24 | } 25 | 26 | type DiskIOCountersStat struct { 27 | ReadCount uint64 `json:"read_count"` 28 | WriteCount uint64 `json:"write_count"` 29 | ReadBytes uint64 `json:"read_bytes"` 30 | WriteBytes uint64 `json:"write_bytes"` 31 | ReadTime uint64 `json:"read_time"` 32 | WriteTime uint64 `json:"write_time"` 33 | Name string `json:"name"` 34 | IoTime uint64 `json:"io_time"` 35 | SerialNumber string `json:"serial_number"` 36 | } 37 | 38 | func (d DiskUsageStat) String() string { 39 | s, _ := json.Marshal(d) 40 | return string(s) 41 | } 42 | 43 | func (d DiskPartitionStat) String() string { 44 | s, _ := json.Marshal(d) 45 | return string(s) 46 | } 47 | 48 | func (d DiskIOCountersStat) String() string { 49 | s, _ := json.Marshal(d) 50 | return string(s) 51 | } 52 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_test.go: -------------------------------------------------------------------------------- 1 | package host 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHostInfo(t *testing.T) { 9 | v, err := HostInfo() 10 | if err != nil { 11 | t.Errorf("error %v", err) 12 | } 13 | empty := &HostInfoStat{} 14 | if v == empty { 15 | t.Errorf("Could not get hostinfo %v", v) 16 | } 17 | } 18 | 19 | func TestBoot_time(t *testing.T) { 20 | v, err := BootTime() 21 | if err != nil { 22 | t.Errorf("error %v", err) 23 | } 24 | if v == 0 { 25 | t.Errorf("Could not boot time %v", v) 26 | } 27 | } 28 | 29 | func TestUsers(t *testing.T) { 30 | v, err := Users() 31 | if err != nil { 32 | t.Errorf("error %v", err) 33 | } 34 | empty := UserStat{} 35 | for _, u := range v { 36 | if u == empty { 37 | t.Errorf("Could not Users %v", v) 38 | } 39 | } 40 | } 41 | 42 | func TestHostInfoStat_String(t *testing.T) { 43 | v := HostInfoStat{ 44 | Hostname: "test", 45 | Uptime: 3000, 46 | Procs: 100, 47 | OS: "linux", 48 | Platform: "ubuntu", 49 | } 50 | e := `{"hostname":"test","uptime":3000,"procs":100,"os":"linux","platform":"ubuntu","platform_family":"","platform_version":"","virtualization_system":"","virtualization_role":""}` 51 | if e != fmt.Sprintf("%v", v) { 52 | t.Errorf("HostInfoStat string is invalid: %v", v) 53 | } 54 | } 55 | 56 | func TestUserStat_String(t *testing.T) { 57 | v := UserStat{ 58 | User: "user", 59 | Terminal: "term", 60 | Host: "host", 61 | Started: 100, 62 | } 63 | e := `{"user":"user","terminal":"term","host":"host","started":100}` 64 | if e != fmt.Sprintf("%v", v) { 65 | t.Errorf("UserStat string is invalid: %v", v) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /plugins/system/ps/LICENSE: -------------------------------------------------------------------------------- 1 | gopsutil is distributed under BSD license reproduced below. 2 | 3 | Copyright (c) 2014, WAKAYAMA Shirou 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of the psutil authors nor the names of its contributors 15 | may be used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_linux_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package host 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestGetRedhatishVersion(t *testing.T) { 10 | var ret string 11 | c := []string{"Rawhide"} 12 | ret = getRedhatishVersion(c) 13 | if ret != "rawhide" { 14 | t.Errorf("Could not get version rawhide: %v", ret) 15 | } 16 | 17 | c = []string{"Fedora release 15 (Lovelock)"} 18 | ret = getRedhatishVersion(c) 19 | if ret != "15" { 20 | t.Errorf("Could not get version fedora: %v", ret) 21 | } 22 | 23 | c = []string{"Enterprise Linux Server release 5.5 (Carthage)"} 24 | ret = getRedhatishVersion(c) 25 | if ret != "5.5" { 26 | t.Errorf("Could not get version redhat enterprise: %v", ret) 27 | } 28 | 29 | c = []string{""} 30 | ret = getRedhatishVersion(c) 31 | if ret != "" { 32 | t.Errorf("Could not get version with no value: %v", ret) 33 | } 34 | } 35 | 36 | func TestGetRedhatishPlatform(t *testing.T) { 37 | var ret string 38 | c := []string{"red hat"} 39 | ret = getRedhatishPlatform(c) 40 | if ret != "redhat" { 41 | t.Errorf("Could not get platform redhat: %v", ret) 42 | } 43 | 44 | c = []string{"Fedora release 15 (Lovelock)"} 45 | ret = getRedhatishPlatform(c) 46 | if ret != "fedora" { 47 | t.Errorf("Could not get platform fedora: %v", ret) 48 | } 49 | 50 | c = []string{"Enterprise Linux Server release 5.5 (Carthage)"} 51 | ret = getRedhatishPlatform(c) 52 | if ret != "enterprise" { 53 | t.Errorf("Could not get platform redhat enterprise: %v", ret) 54 | } 55 | 56 | c = []string{""} 57 | ret = getRedhatishPlatform(c) 58 | if ret != "" { 59 | t.Errorf("Could not get platform with no value: %v", ret) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /plugins/prometheus/prometheus_test.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | 9 | "github.com/influxdb/telegraf/testutil" 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | 15 | const sampleTextFormat = `# HELP go_gc_duration_seconds A summary of the GC invocation durations. 16 | # TYPE go_gc_duration_seconds summary 17 | go_gc_duration_seconds{quantile="0"} 0.00010425500000000001 18 | go_gc_duration_seconds{quantile="0.25"} 0.000139108 19 | go_gc_duration_seconds{quantile="0.5"} 0.00015749400000000002 20 | go_gc_duration_seconds{quantile="0.75"} 0.000331463 21 | go_gc_duration_seconds{quantile="1"} 0.000667154 22 | go_gc_duration_seconds_sum 0.0018183950000000002 23 | go_gc_duration_seconds_count 7 24 | # HELP go_goroutines Number of goroutines that currently exist. 25 | # TYPE go_goroutines gauge 26 | go_goroutines 15 27 | ` 28 | 29 | func TestPrometheusGeneratesMetrics(t *testing.T) { 30 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 31 | fmt.Fprintln(w, sampleTextFormat) 32 | })) 33 | defer ts.Close() 34 | 35 | p := &Prometheus{ 36 | Urls: []string{ts.URL}, 37 | } 38 | 39 | var acc testutil.Accumulator 40 | 41 | err := p.Gather(&acc) 42 | require.NoError(t, err) 43 | 44 | expected := []struct { 45 | name string 46 | value float64 47 | tags map[string]string 48 | }{ 49 | {"go_gc_duration_seconds_count", 7, map[string]string{}}, 50 | {"go_goroutines", 15, map[string]string{}}, 51 | } 52 | 53 | for _, e := range expected { 54 | assert.NoError(t, acc.ValidateValue(e.name, e.value)) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package net 4 | 5 | import ( 6 | "os/exec" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/influxdb/telegraf/plugins/system/ps/common" 11 | ) 12 | 13 | func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { 14 | out, err := exec.Command("/usr/sbin/netstat", "-ibdn").Output() 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | lines := strings.Split(string(out), "\n") 20 | ret := make([]NetIOCountersStat, 0, len(lines)-1) 21 | exists := make([]string, 0, len(ret)) 22 | 23 | for _, line := range lines { 24 | values := strings.Fields(line) 25 | if len(values) < 1 || values[0] == "Name" { 26 | // skip first line 27 | continue 28 | } 29 | if common.StringContains(exists, values[0]) { 30 | // skip if already get 31 | continue 32 | } 33 | exists = append(exists, values[0]) 34 | 35 | base := 1 36 | // sometimes Address is ommitted 37 | if len(values) < 11 { 38 | base = 0 39 | } 40 | 41 | parsed := make([]uint64, 0, 3) 42 | vv := []string{ 43 | values[base+3], // PacketsRecv 44 | values[base+4], // Errin 45 | values[base+5], // Dropin 46 | } 47 | for _, target := range vv { 48 | if target == "-" { 49 | parsed = append(parsed, 0) 50 | continue 51 | } 52 | 53 | t, err := strconv.ParseUint(target, 10, 64) 54 | if err != nil { 55 | return nil, err 56 | } 57 | parsed = append(parsed, t) 58 | } 59 | 60 | n := NetIOCountersStat{ 61 | Name: values[0], 62 | PacketsRecv: parsed[0], 63 | Errin: parsed[1], 64 | Dropin: parsed[2], 65 | } 66 | ret = append(ret, n) 67 | } 68 | 69 | if pernic == false { 70 | return getNetIOCountersAll(ret) 71 | } 72 | 73 | return ret, nil 74 | } 75 | -------------------------------------------------------------------------------- /plugins/system/ps/docker/docker.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import "errors" 4 | 5 | var ErrNotAvailable = errors.New("docker not available") 6 | 7 | type CgroupMemStat struct { 8 | ContainerID string `json:"container_id"` 9 | Cache uint64 `json:"cache"` 10 | RSS uint64 `json:"rss"` 11 | RSSHuge uint64 `json:"rss_huge"` 12 | MappedFile uint64 `json:"mapped_file"` 13 | Pgpgin uint64 `json:"pgpgin"` 14 | Pgpgout uint64 `json:"pgpgout"` 15 | Pgfault uint64 `json:"pgfault"` 16 | Pgmajfault uint64 `json:"pgmajfault"` 17 | InactiveAnon uint64 `json:"inactive_anon"` 18 | ActiveAnon uint64 `json:"active_anon"` 19 | InactiveFile uint64 `json:"inactive_file"` 20 | ActiveFile uint64 `json:"active_file"` 21 | Unevictable uint64 `json:"unevictable"` 22 | HierarchicalMemoryLimit uint64 `json:"hierarchical_memory_limit"` 23 | TotalCache uint64 `json:"total_cache"` 24 | TotalRSS uint64 `json:"total_rss"` 25 | TotalRSSHuge uint64 `json:"total_rss_huge"` 26 | TotalMappedFile uint64 `json:"total_mapped_file"` 27 | TotalPgpgIn uint64 `json:"total_pgpgin"` 28 | TotalPgpgOut uint64 `json:"total_pgpgout"` 29 | TotalPgFault uint64 `json:"total_pgfault"` 30 | TotalPgMajFault uint64 `json:"total_pgmajfault"` 31 | TotalInactiveAnon uint64 `json:"total_inactive_anon"` 32 | TotalActiveAnon uint64 `json:"total_active_anon"` 33 | TotalInactiveFile uint64 `json:"total_inactive_file"` 34 | TotalActiveFile uint64 `json:"total_active_file"` 35 | TotalUnevictable uint64 `json:"total_unevictable"` 36 | } 37 | -------------------------------------------------------------------------------- /plugins/kafka_consumer/kafka_consumer_integration_test.go: -------------------------------------------------------------------------------- 1 | package kafka_consumer 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "testing" 8 | "time" 9 | 10 | "github.com/Shopify/sarama" 11 | "github.com/influxdb/telegraf/testutil" 12 | "github.com/stretchr/testify/assert" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | func TestReadsMetricsFromKafka(t *testing.T) { 17 | var zkPeers, brokerPeers []string 18 | 19 | if len(os.Getenv("ZOOKEEPER_PEERS")) == 0 { 20 | zkPeers = []string{"localhost:2181"} 21 | } else { 22 | zkPeers = strings.Split(os.Getenv("ZOOKEEPER_PEERS"), ",") 23 | } 24 | 25 | if len(os.Getenv("KAFKA_PEERS")) == 0 { 26 | brokerPeers = []string{"localhost:9092"} 27 | } else { 28 | brokerPeers = strings.Split(os.Getenv("KAFKA_PEERS"), ",") 29 | } 30 | 31 | k := &Kafka{ 32 | ConsumerGroupName: "telegraf_test_consumers", 33 | Topic: fmt.Sprintf("telegraf_test_topic_%d", time.Now().Unix()), 34 | ZookeeperPeers: zkPeers, 35 | } 36 | 37 | msg := "cpu_load_short,direction=in,host=server01,region=us-west value=23422.0 1422568543702900257" 38 | producer, err := sarama.NewSyncProducer(brokerPeers, nil) 39 | require.NoError(t, err) 40 | _, _, err = producer.SendMessage(&sarama.ProducerMessage{Topic: k.Topic, Value: sarama.StringEncoder(msg)}) 41 | producer.Close() 42 | 43 | var acc testutil.Accumulator 44 | 45 | // Sanity check 46 | assert.Equal(t, 0, len(acc.Points), "there should not be any points") 47 | 48 | err = k.Gather(&acc) 49 | require.NoError(t, err) 50 | 51 | assert.Equal(t, 1, len(acc.Points), "there should be a single point") 52 | 53 | point := acc.Points[0] 54 | assert.Equal(t, "cpu_load_short", point.Measurement) 55 | assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Values) 56 | assert.Equal(t, map[string]string{ 57 | "host": "server01", 58 | "direction": "in", 59 | "region": "us-west", 60 | }, point.Tags) 61 | assert.Equal(t, time.Unix(0, 1422568543702900257), point.Time) 62 | } 63 | -------------------------------------------------------------------------------- /plugins/system/mock_PS.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import "github.com/stretchr/testify/mock" 4 | 5 | import "github.com/influxdb/telegraf/plugins/system/ps/cpu" 6 | import "github.com/influxdb/telegraf/plugins/system/ps/disk" 7 | 8 | import "github.com/influxdb/telegraf/plugins/system/ps/load" 9 | import "github.com/influxdb/telegraf/plugins/system/ps/mem" 10 | import "github.com/influxdb/telegraf/plugins/system/ps/net" 11 | 12 | type MockPS struct { 13 | mock.Mock 14 | } 15 | 16 | func (m *MockPS) LoadAvg() (*load.LoadAvgStat, error) { 17 | ret := m.Called() 18 | 19 | r0 := ret.Get(0).(*load.LoadAvgStat) 20 | r1 := ret.Error(1) 21 | 22 | return r0, r1 23 | } 24 | func (m *MockPS) CPUTimes() ([]cpu.CPUTimesStat, error) { 25 | ret := m.Called() 26 | 27 | r0 := ret.Get(0).([]cpu.CPUTimesStat) 28 | r1 := ret.Error(1) 29 | 30 | return r0, r1 31 | } 32 | func (m *MockPS) DiskUsage() ([]*disk.DiskUsageStat, error) { 33 | ret := m.Called() 34 | 35 | r0 := ret.Get(0).([]*disk.DiskUsageStat) 36 | r1 := ret.Error(1) 37 | 38 | return r0, r1 39 | } 40 | func (m *MockPS) NetIO() ([]net.NetIOCountersStat, error) { 41 | ret := m.Called() 42 | 43 | r0 := ret.Get(0).([]net.NetIOCountersStat) 44 | r1 := ret.Error(1) 45 | 46 | return r0, r1 47 | } 48 | func (m *MockPS) DiskIO() (map[string]disk.DiskIOCountersStat, error) { 49 | ret := m.Called() 50 | 51 | r0 := ret.Get(0).(map[string]disk.DiskIOCountersStat) 52 | r1 := ret.Error(1) 53 | 54 | return r0, r1 55 | } 56 | func (m *MockPS) VMStat() (*mem.VirtualMemoryStat, error) { 57 | ret := m.Called() 58 | 59 | r0 := ret.Get(0).(*mem.VirtualMemoryStat) 60 | r1 := ret.Error(1) 61 | 62 | return r0, r1 63 | } 64 | func (m *MockPS) SwapStat() (*mem.SwapMemoryStat, error) { 65 | ret := m.Called() 66 | 67 | r0 := ret.Get(0).(*mem.SwapMemoryStat) 68 | r1 := ret.Error(1) 69 | 70 | return r0, r1 71 | } 72 | func (m *MockPS) DockerStat() ([]*DockerContainerStat, error) { 73 | ret := m.Called() 74 | 75 | r0 := ret.Get(0).([]*DockerContainerStat) 76 | r1 := ret.Error(1) 77 | 78 | return r0, r1 79 | } 80 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_darwin_amd64.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | // +build amd64 3 | 4 | package disk 5 | 6 | const ( 7 | MntWait = 1 8 | MfsNameLen = 15 /* length of fs type name, not inc. nul */ 9 | MNameLen = 90 /* length of buffer for returned name */ 10 | 11 | MFSTYPENAMELEN = 16 /* length of fs type name including null */ 12 | MAXPATHLEN = 1024 13 | MNAMELEN = MAXPATHLEN 14 | 15 | SYS_GETFSSTAT64 = 347 16 | ) 17 | 18 | type Fsid struct{ val [2]int32 } /* file system id type */ 19 | type uid_t int32 20 | 21 | // sys/mount.h 22 | const ( 23 | MntReadOnly = 0x00000001 /* read only filesystem */ 24 | MntSynchronous = 0x00000002 /* filesystem written synchronously */ 25 | MntNoExec = 0x00000004 /* can't exec from filesystem */ 26 | MntNoSuid = 0x00000008 /* don't honor setuid bits on fs */ 27 | MntUnion = 0x00000020 /* union with underlying filesystem */ 28 | MntAsync = 0x00000040 /* filesystem written asynchronously */ 29 | MntSuidDir = 0x00100000 /* special handling of SUID on dirs */ 30 | MntSoftDep = 0x00200000 /* soft updates being done */ 31 | MntNoSymFollow = 0x00400000 /* do not follow symlinks */ 32 | MntGEOMJournal = 0x02000000 /* GEOM journal support enabled */ 33 | MntMultilabel = 0x04000000 /* MAC support for individual objects */ 34 | MntACLs = 0x08000000 /* ACL support enabled */ 35 | MntNoATime = 0x10000000 /* disable update of file access time */ 36 | MntClusterRead = 0x40000000 /* disable cluster read */ 37 | MntClusterWrite = 0x80000000 /* disable cluster write */ 38 | MntNFS4ACLs = 0x00000010 39 | ) 40 | 41 | type Statfs_t struct { 42 | Bsize uint32 43 | Iosize int32 44 | Blocks uint64 45 | Bfree uint64 46 | Bavail uint64 47 | Files uint64 48 | Ffree uint64 49 | Fsid Fsid 50 | Owner uint32 51 | Type uint32 52 | Flags uint32 53 | Fssubtype uint32 54 | Fstypename [16]int8 55 | Mntonname [1024]int8 56 | Mntfromname [1024]int8 57 | Reserved [8]uint32 58 | } 59 | -------------------------------------------------------------------------------- /plugins/rethinkdb/rethinkdb_server_test.go: -------------------------------------------------------------------------------- 1 | // +build integration 2 | 3 | package rethinkdb 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/influxdb/telegraf/testutil" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func TestValidateVersion(t *testing.T) { 14 | err := server.validateVersion() 15 | require.NoError(t, err) 16 | } 17 | 18 | func TestGetDefaultTags(t *testing.T) { 19 | var tagTests = []struct { 20 | in string 21 | out string 22 | }{ 23 | {"host", server.Url.Host}, 24 | {"hostname", server.serverStatus.Network.Hostname}, 25 | } 26 | defaultTags := server.getDefaultTags() 27 | for _, tt := range tagTests { 28 | if defaultTags[tt.in] != tt.out { 29 | t.Errorf("expected %q, got %q", tt.out, defaultTags[tt.in]) 30 | } 31 | } 32 | } 33 | 34 | func TestAddClusterStats(t *testing.T) { 35 | var acc testutil.Accumulator 36 | 37 | err := server.addClusterStats(&acc) 38 | require.NoError(t, err) 39 | 40 | for _, metric := range ClusterTracking { 41 | assert.True(t, acc.HasIntValue(metric)) 42 | } 43 | } 44 | 45 | func TestAddMemberStats(t *testing.T) { 46 | var acc testutil.Accumulator 47 | 48 | err := server.addMemberStats(&acc) 49 | require.NoError(t, err) 50 | 51 | for _, metric := range MemberTracking { 52 | assert.True(t, acc.HasIntValue(metric)) 53 | } 54 | } 55 | 56 | func TestAddTableStats(t *testing.T) { 57 | var acc testutil.Accumulator 58 | 59 | err := server.addTableStats(&acc) 60 | require.NoError(t, err) 61 | 62 | for _, metric := range TableTracking { 63 | assert.True(t, acc.HasIntValue(metric)) 64 | } 65 | 66 | keys := []string{ 67 | "cache_bytes_in_use", 68 | "disk_read_bytes_per_sec", 69 | "disk_read_bytes_total", 70 | "disk_written_bytes_per_sec", 71 | "disk_written_bytes_total", 72 | "disk_usage_data_bytes", 73 | "disk_usage_garbage_bytes", 74 | "disk_usage_metadata_bytes", 75 | "disk_usage_preallocated_bytes", 76 | } 77 | 78 | for _, metric := range keys { 79 | assert.True(t, acc.HasIntValue(metric)) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package net 4 | 5 | import ( 6 | "os/exec" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/influxdb/telegraf/plugins/system/ps/common" 11 | ) 12 | 13 | func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { 14 | out, err := exec.Command("/usr/bin/netstat", "-ibdn").Output() 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | lines := strings.Split(string(out), "\n") 20 | ret := make([]NetIOCountersStat, 0, len(lines)-1) 21 | exists := make([]string, 0, len(ret)) 22 | 23 | for _, line := range lines { 24 | values := strings.Fields(line) 25 | if len(values) < 1 || values[0] == "Name" { 26 | continue 27 | } 28 | if common.StringContains(exists, values[0]) { 29 | // skip if already get 30 | continue 31 | } 32 | exists = append(exists, values[0]) 33 | 34 | base := 1 35 | // sometimes Address is ommitted 36 | if len(values) < 13 { 37 | base = 0 38 | } 39 | 40 | parsed := make([]uint64, 0, 8) 41 | vv := []string{ 42 | values[base+3], // PacketsRecv 43 | values[base+4], // Errin 44 | values[base+5], // Dropin 45 | values[base+6], // BytesRecvn 46 | values[base+7], // PacketSent 47 | values[base+8], // Errout 48 | values[base+9], // BytesSent 49 | values[base+11], // Dropout 50 | } 51 | for _, target := range vv { 52 | if target == "-" { 53 | parsed = append(parsed, 0) 54 | continue 55 | } 56 | 57 | t, err := strconv.ParseUint(target, 10, 64) 58 | if err != nil { 59 | return nil, err 60 | } 61 | parsed = append(parsed, t) 62 | } 63 | 64 | n := NetIOCountersStat{ 65 | Name: values[0], 66 | PacketsRecv: parsed[0], 67 | Errin: parsed[1], 68 | Dropin: parsed[2], 69 | BytesRecv: parsed[3], 70 | PacketsSent: parsed[4], 71 | Errout: parsed[5], 72 | BytesSent: parsed[6], 73 | Dropout: parsed[7], 74 | } 75 | ret = append(ret, n) 76 | } 77 | 78 | if pernic == false { 79 | return getNetIOCountersAll(ret) 80 | } 81 | 82 | return ret, nil 83 | } 84 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.1.4 [2015-07-09] 2 | 3 | ### Features 4 | - [#56](https://github.com/influxdb/telegraf/pull/56): Update README for Kafka plugin. Thanks @EmilS! 5 | 6 | ### Bugfixes 7 | - [#50](https://github.com/influxdb/telegraf/pull/50): Fix init.sh script to use telegraf directory. Thanks @jseriff! 8 | - [#52](https://github.com/influxdb/telegraf/pull/52): Update CHANGELOG to reference updated directory. Thanks @benfb! 9 | 10 | ## v0.1.3 [2015-07-05] 11 | 12 | ### Features 13 | - [#35](https://github.com/influxdb/telegraf/pull/35): Add Kafka plugin. Thanks @EmilS! 14 | - [#47](https://github.com/influxdb/telegraf/pull/47): Add RethinkDB plugin. Thanks @jipperinbham! 15 | 16 | ### Bugfixes 17 | - [#45](https://github.com/influxdb/telegraf/pull/45): Skip disk tags that don't have a value. Thanks @jhofeditz! 18 | - [#43](https://github.com/influxdb/telegraf/pull/43): Fix bug in MySQL plugin. Thanks @marcosnils! 19 | 20 | ## v0.1.2 [2015-07-01] 21 | 22 | ### Features 23 | - [#12](https://github.com/influxdb/telegraf/pull/12): Add Linux/ARM to the list of built binaries. Thanks @voxxit! 24 | - [#14](https://github.com/influxdb/telegraf/pull/14): Clarify the S3 buckets that Telegraf is pushed to. 25 | - [#16](https://github.com/influxdb/telegraf/pull/16): Convert Redis to use URI, support Redis AUTH. Thanks @jipperinbham! 26 | - [#21](https://github.com/influxdb/telegraf/pull/21): Add memcached plugin. Thanks @Yukki! 27 | 28 | ### Bugfixes 29 | - [#13](https://github.com/influxdb/telegraf/pull/13): Fix the packaging script. 30 | - [#19](https://github.com/influxdb/telegraf/pull/19): Add host name to metric tags. Thanks @sherifzain! 31 | - [#20](https://github.com/influxdb/telegraf/pull/20): Fix race condition with accumulator mutex. Thanks @nkatsaros! 32 | - [#23](https://github.com/influxdb/telegraf/pull/23): Change name of folder for packages. Thanks @colinrymer! 33 | - [#32](https://github.com/influxdb/telegraf/pull/32): Fix spelling of memoory -> memory. Thanks @tylernisonoff! 34 | 35 | ## v0.1.1 [2015-06-19] 36 | 37 | ### Release Notes 38 | 39 | This is the initial release of Telegraf. 40 | -------------------------------------------------------------------------------- /plugins/system/memory.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/influxdb/telegraf/plugins" 7 | ) 8 | 9 | type MemStats struct { 10 | ps PS 11 | } 12 | 13 | func (_ *MemStats) Description() string { 14 | return "Read metrics about memory usage" 15 | } 16 | 17 | func (_ *MemStats) SampleConfig() string { return "" } 18 | 19 | func (s *MemStats) Gather(acc plugins.Accumulator) error { 20 | vm, err := s.ps.VMStat() 21 | if err != nil { 22 | return fmt.Errorf("error getting virtual memory info: %s", err) 23 | } 24 | 25 | vmtags := map[string]string(nil) 26 | 27 | acc.Add("total", vm.Total, vmtags) 28 | acc.Add("available", vm.Available, vmtags) 29 | acc.Add("used", vm.Used, vmtags) 30 | acc.Add("used_prec", vm.UsedPercent, vmtags) 31 | acc.Add("free", vm.Free, vmtags) 32 | acc.Add("active", vm.Active, vmtags) 33 | acc.Add("inactive", vm.Inactive, vmtags) 34 | acc.Add("buffers", vm.Buffers, vmtags) 35 | acc.Add("cached", vm.Cached, vmtags) 36 | acc.Add("wired", vm.Wired, vmtags) 37 | acc.Add("shared", vm.Shared, vmtags) 38 | 39 | return nil 40 | } 41 | 42 | type SwapStats struct { 43 | ps PS 44 | } 45 | 46 | func (_ *SwapStats) Description() string { 47 | return "Read metrics about swap memory usage" 48 | } 49 | 50 | func (_ *SwapStats) SampleConfig() string { return "" } 51 | 52 | func (s *SwapStats) Gather(acc plugins.Accumulator) error { 53 | swap, err := s.ps.SwapStat() 54 | if err != nil { 55 | return fmt.Errorf("error getting swap memory info: %s", err) 56 | } 57 | 58 | swaptags := map[string]string(nil) 59 | 60 | acc.Add("total", swap.Total, swaptags) 61 | acc.Add("used", swap.Used, swaptags) 62 | acc.Add("free", swap.Free, swaptags) 63 | acc.Add("used_perc", swap.UsedPercent, swaptags) 64 | acc.Add("in", swap.Sin, swaptags) 65 | acc.Add("out", swap.Sout, swaptags) 66 | 67 | return nil 68 | } 69 | 70 | func init() { 71 | plugins.Add("mem", func() plugins.Plugin { 72 | return &MemStats{ps: &systemPS{}} 73 | }) 74 | 75 | plugins.Add("swap", func() plugins.Plugin { 76 | return &SwapStats{ps: &systemPS{}} 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /plugins/system/net.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "github.com/influxdb/telegraf/plugins" 8 | ) 9 | 10 | type NetIOStats struct { 11 | ps PS 12 | 13 | skipChecks bool 14 | Interfaces []string 15 | } 16 | 17 | func (_ *NetIOStats) Description() string { 18 | return "Read metrics about network interface usage" 19 | } 20 | 21 | var netSampleConfig = ` 22 | # By default, telegraf gathers stats from any up interface (excluding loopback) 23 | # Setting interfaces will tell it to gather these explicit interfaces, 24 | # regardless of status. 25 | # 26 | # interfaces = ["eth0", ... ] 27 | ` 28 | 29 | func (_ *NetIOStats) SampleConfig() string { 30 | return netSampleConfig 31 | } 32 | 33 | func (s *NetIOStats) Gather(acc plugins.Accumulator) error { 34 | netio, err := s.ps.NetIO() 35 | if err != nil { 36 | return fmt.Errorf("error getting net io info: %s", err) 37 | } 38 | 39 | for _, io := range netio { 40 | if len(s.Interfaces) != 0 { 41 | var found bool 42 | 43 | for _, name := range s.Interfaces { 44 | if name == io.Name { 45 | found = true 46 | break 47 | } 48 | } 49 | 50 | if !found { 51 | continue 52 | } 53 | } else if !s.skipChecks { 54 | iface, err := net.InterfaceByName(io.Name) 55 | if err != nil { 56 | continue 57 | } 58 | 59 | if iface.Flags&net.FlagLoopback == net.FlagLoopback { 60 | continue 61 | } 62 | 63 | if iface.Flags&net.FlagUp == 0 { 64 | continue 65 | } 66 | } 67 | 68 | tags := map[string]string{ 69 | "interface": io.Name, 70 | } 71 | 72 | acc.Add("bytes_sent", io.BytesSent, tags) 73 | acc.Add("bytes_recv", io.BytesRecv, tags) 74 | acc.Add("packets_sent", io.PacketsSent, tags) 75 | acc.Add("packets_recv", io.PacketsRecv, tags) 76 | acc.Add("err_in", io.Errin, tags) 77 | acc.Add("err_out", io.Errout, tags) 78 | acc.Add("drop_in", io.Dropin, tags) 79 | acc.Add("drop_out", io.Dropout, tags) 80 | } 81 | 82 | return nil 83 | } 84 | 85 | func init() { 86 | plugins.Add("net", func() plugins.Plugin { 87 | return &NetIOStats{ps: &systemPS{}} 88 | }) 89 | } 90 | -------------------------------------------------------------------------------- /accumulator.go: -------------------------------------------------------------------------------- 1 | package telegraf 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | "strings" 7 | "sync" 8 | "time" 9 | 10 | "github.com/influxdb/influxdb/client" 11 | ) 12 | 13 | type BatchPoints struct { 14 | mu sync.Mutex 15 | 16 | client.BatchPoints 17 | 18 | Debug bool 19 | 20 | Prefix string 21 | 22 | Config *ConfiguredPlugin 23 | } 24 | 25 | func (bp *BatchPoints) Add(measurement string, val interface{}, tags map[string]string) { 26 | bp.mu.Lock() 27 | defer bp.mu.Unlock() 28 | 29 | measurement = bp.Prefix + measurement 30 | 31 | if bp.Config != nil { 32 | if !bp.Config.ShouldPass(measurement) { 33 | return 34 | } 35 | } 36 | 37 | if bp.Debug { 38 | var tg []string 39 | 40 | for k, v := range tags { 41 | tg = append(tg, fmt.Sprintf("%s=\"%s\"", k, v)) 42 | } 43 | 44 | sort.Strings(tg) 45 | 46 | fmt.Printf("> [%s] %s value=%v\n", strings.Join(tg, " "), measurement, val) 47 | } 48 | 49 | bp.Points = append(bp.Points, client.Point{ 50 | Measurement: measurement, 51 | Tags: tags, 52 | Fields: map[string]interface{}{ 53 | "value": val, 54 | }, 55 | }) 56 | } 57 | 58 | func (bp *BatchPoints) AddValuesWithTime( 59 | measurement string, 60 | values map[string]interface{}, 61 | tags map[string]string, 62 | timestamp time.Time, 63 | ) { 64 | bp.mu.Lock() 65 | defer bp.mu.Unlock() 66 | 67 | measurement = bp.Prefix + measurement 68 | 69 | if bp.Config != nil { 70 | if !bp.Config.ShouldPass(measurement) { 71 | return 72 | } 73 | } 74 | 75 | if bp.Debug { 76 | var tg []string 77 | 78 | for k, v := range tags { 79 | tg = append(tg, fmt.Sprintf("%s=\"%s\"", k, v)) 80 | } 81 | 82 | var vals []string 83 | 84 | for k, v := range values { 85 | vals = append(vals, fmt.Sprintf("%s=%v", k, v)) 86 | } 87 | 88 | sort.Strings(tg) 89 | sort.Strings(vals) 90 | 91 | fmt.Printf("> [%s] %s %s\n", strings.Join(tg, " "), measurement, strings.Join(vals, " ")) 92 | } 93 | 94 | bp.Points = append(bp.Points, client.Point{ 95 | Measurement: measurement, 96 | Tags: tags, 97 | Fields: values, 98 | Time: timestamp, 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /plugins/system/disk.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/influxdb/telegraf/plugins" 7 | ) 8 | 9 | type DiskStats struct { 10 | ps PS 11 | } 12 | 13 | func (_ *DiskStats) Description() string { 14 | return "Read metrics about disk usage by mount point" 15 | } 16 | 17 | func (_ *DiskStats) SampleConfig() string { return "" } 18 | 19 | func (s *DiskStats) Gather(acc plugins.Accumulator) error { 20 | disks, err := s.ps.DiskUsage() 21 | if err != nil { 22 | return fmt.Errorf("error getting disk usage info: %s", err) 23 | } 24 | 25 | for _, du := range disks { 26 | tags := map[string]string{ 27 | "path": du.Path, 28 | } 29 | 30 | acc.Add("total", du.Total, tags) 31 | acc.Add("free", du.Free, tags) 32 | acc.Add("used", du.Total-du.Free, tags) 33 | acc.Add("inodes_total", du.InodesTotal, tags) 34 | acc.Add("inodes_free", du.InodesFree, tags) 35 | acc.Add("inodes_used", du.InodesTotal-du.InodesFree, tags) 36 | } 37 | 38 | return nil 39 | } 40 | 41 | type DiskIOStats struct { 42 | ps PS 43 | } 44 | 45 | func (_ *DiskIOStats) Description() string { 46 | return "Read metrics about disk IO by device" 47 | } 48 | 49 | func (_ *DiskIOStats) SampleConfig() string { return "" } 50 | 51 | func (s *DiskIOStats) Gather(acc plugins.Accumulator) error { 52 | diskio, err := s.ps.DiskIO() 53 | if err != nil { 54 | return fmt.Errorf("error getting disk io info: %s", err) 55 | } 56 | 57 | for _, io := range diskio { 58 | tags := map[string]string{} 59 | if len(io.Name) != 0 { 60 | tags["name"] = io.Name 61 | } 62 | if len(io.SerialNumber) != 0 { 63 | tags["serial"] = io.SerialNumber 64 | } 65 | 66 | acc.Add("reads", io.ReadCount, tags) 67 | acc.Add("writes", io.WriteCount, tags) 68 | acc.Add("read_bytes", io.ReadBytes, tags) 69 | acc.Add("write_bytes", io.WriteBytes, tags) 70 | acc.Add("read_time", io.ReadTime, tags) 71 | acc.Add("write_time", io.WriteTime, tags) 72 | acc.Add("io_time", io.IoTime, tags) 73 | } 74 | 75 | return nil 76 | } 77 | 78 | func init() { 79 | plugins.Add("disk", func() plugins.Plugin { 80 | return &DiskStats{ps: &systemPS{}} 81 | }) 82 | 83 | plugins.Add("io", func() plugins.Plugin { 84 | return &DiskIOStats{ps: &systemPS{}} 85 | }) 86 | } 87 | -------------------------------------------------------------------------------- /plugins/system/ps/common/common_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestReadlines(t *testing.T) { 10 | ret, err := ReadLines("common_test.go") 11 | if err != nil { 12 | t.Error(err) 13 | } 14 | if !strings.Contains(ret[0], "package common") { 15 | t.Error("could not read correctly") 16 | } 17 | } 18 | 19 | func TestReadLinesOffsetN(t *testing.T) { 20 | ret, err := ReadLinesOffsetN("common_test.go", 2, 1) 21 | if err != nil { 22 | t.Error(err) 23 | } 24 | fmt.Println(ret[0]) 25 | if !strings.Contains(ret[0], `import (`) { 26 | t.Error("could not read correctly") 27 | } 28 | } 29 | 30 | func TestIntToString(t *testing.T) { 31 | src := []int8{65, 66, 67} 32 | dst := IntToString(src) 33 | if dst != "ABC" { 34 | t.Error("could not convert") 35 | } 36 | } 37 | func TestByteToString(t *testing.T) { 38 | src := []byte{65, 66, 67} 39 | dst := ByteToString(src) 40 | if dst != "ABC" { 41 | t.Error("could not convert") 42 | } 43 | 44 | src = []byte{0, 65, 66, 67} 45 | dst = ByteToString(src) 46 | if dst != "ABC" { 47 | t.Error("could not convert") 48 | } 49 | } 50 | 51 | func TestmustParseInt32(t *testing.T) { 52 | ret := mustParseInt32("11111") 53 | if ret != int32(11111) { 54 | t.Error("could not parse") 55 | } 56 | } 57 | func TestmustParseUint64(t *testing.T) { 58 | ret := mustParseUint64("11111") 59 | if ret != uint64(11111) { 60 | t.Error("could not parse") 61 | } 62 | } 63 | func TestmustParseFloat64(t *testing.T) { 64 | ret := mustParseFloat64("11111.11") 65 | if ret != float64(11111.11) { 66 | t.Error("could not parse") 67 | } 68 | ret = mustParseFloat64("11111") 69 | if ret != float64(11111) { 70 | t.Error("could not parse") 71 | } 72 | } 73 | func TestStringContains(t *testing.T) { 74 | target, err := ReadLines("common_test.go") 75 | if err != nil { 76 | t.Error(err) 77 | } 78 | if !StringContains(target, "func TestStringContains(t *testing.T) {") { 79 | t.Error("cloud not test correctly") 80 | } 81 | } 82 | 83 | func TestPathExists(t *testing.T) { 84 | if !PathExists("common_test.go") { 85 | t.Error("exists but return not exists") 86 | } 87 | if PathExists("should_not_exists.go") { 88 | t.Error("not exists but return exists") 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /plugins/postgresql/postgresql_test.go: -------------------------------------------------------------------------------- 1 | package postgresql 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/influxdb/telegraf/testutil" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestPostgresqlGeneratesMetrics(t *testing.T) { 12 | p := &Postgresql{ 13 | Servers: []*Server{ 14 | { 15 | Address: "sslmode=disable", 16 | Databases: []string{"postgres"}, 17 | }, 18 | }, 19 | } 20 | 21 | var acc testutil.Accumulator 22 | 23 | err := p.Gather(&acc) 24 | require.NoError(t, err) 25 | 26 | intMetrics := []string{ 27 | "xact_commit", 28 | "xact_rollback", 29 | "blks_read", 30 | "blks_hit", 31 | "tup_returned", 32 | "tup_fetched", 33 | "tup_inserted", 34 | "tup_updated", 35 | "tup_deleted", 36 | "conflicts", 37 | "temp_files", 38 | "temp_bytes", 39 | "deadlocks", 40 | } 41 | 42 | floatMetrics := []string{ 43 | "blk_read_time", 44 | "blk_write_time", 45 | } 46 | 47 | for _, metric := range intMetrics { 48 | assert.True(t, acc.HasIntValue(metric)) 49 | } 50 | 51 | for _, metric := range floatMetrics { 52 | assert.True(t, acc.HasFloatValue(metric)) 53 | } 54 | } 55 | 56 | func TestPostgresqlTagsMetricsWithDatabaseName(t *testing.T) { 57 | p := &Postgresql{ 58 | Servers: []*Server{ 59 | { 60 | Address: "sslmode=disable", 61 | Databases: []string{"postgres"}, 62 | }, 63 | }, 64 | } 65 | 66 | var acc testutil.Accumulator 67 | 68 | err := p.Gather(&acc) 69 | require.NoError(t, err) 70 | 71 | point, ok := acc.Get("xact_commit") 72 | require.True(t, ok) 73 | 74 | assert.Equal(t, "postgres", point.Tags["db"]) 75 | } 76 | 77 | func TestPostgresqlDefaultsToAllDatabases(t *testing.T) { 78 | p := &Postgresql{ 79 | Servers: []*Server{ 80 | { 81 | Address: "sslmode=disable", 82 | }, 83 | }, 84 | } 85 | 86 | var acc testutil.Accumulator 87 | 88 | err := p.Gather(&acc) 89 | require.NoError(t, err) 90 | 91 | var found bool 92 | 93 | for _, pnt := range acc.Points { 94 | if pnt.Measurement == "xact_commit" { 95 | if pnt.Tags["db"] == "postgres" { 96 | found = true 97 | break 98 | } 99 | } 100 | } 101 | 102 | assert.True(t, found) 103 | } 104 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package mem 4 | 5 | import ( 6 | "strconv" 7 | "strings" 8 | "syscall" 9 | 10 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 11 | ) 12 | 13 | func VirtualMemory() (*VirtualMemoryStat, error) { 14 | filename := "/proc/meminfo" 15 | lines, _ := common.ReadLines(filename) 16 | 17 | ret := &VirtualMemoryStat{} 18 | for _, line := range lines { 19 | fields := strings.Split(line, ":") 20 | if len(fields) != 2 { 21 | continue 22 | } 23 | key := strings.TrimSpace(fields[0]) 24 | value := strings.TrimSpace(fields[1]) 25 | value = strings.Replace(value, " kB", "", -1) 26 | 27 | t, err := strconv.ParseUint(value, 10, 64) 28 | if err != nil { 29 | return ret, err 30 | } 31 | switch key { 32 | case "MemTotal": 33 | ret.Total = t * 1000 34 | case "MemFree": 35 | ret.Free = t * 1000 36 | case "Buffers": 37 | ret.Buffers = t * 1000 38 | case "Cached": 39 | ret.Cached = t * 1000 40 | case "Active": 41 | ret.Active = t * 1000 42 | case "Inactive": 43 | ret.Inactive = t * 1000 44 | } 45 | } 46 | ret.Available = ret.Free + ret.Buffers + ret.Cached 47 | ret.Used = ret.Total - ret.Free 48 | ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 49 | 50 | return ret, nil 51 | } 52 | 53 | func SwapMemory() (*SwapMemoryStat, error) { 54 | sysinfo := &syscall.Sysinfo_t{} 55 | 56 | if err := syscall.Sysinfo(sysinfo); err != nil { 57 | return nil, err 58 | } 59 | ret := &SwapMemoryStat{ 60 | Total: uint64(sysinfo.Totalswap), 61 | Free: uint64(sysinfo.Freeswap), 62 | } 63 | ret.Used = ret.Total - ret.Free 64 | //check Infinity 65 | if ret.Total != 0 { 66 | ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0 67 | } else { 68 | ret.UsedPercent = 0 69 | } 70 | lines, _ := common.ReadLines("/proc/vmstat") 71 | for _, l := range lines { 72 | fields := strings.Fields(l) 73 | if len(fields) < 2 { 74 | continue 75 | } 76 | switch fields[0] { 77 | case "pswpin": 78 | value, err := strconv.ParseUint(fields[1], 10, 64) 79 | if err != nil { 80 | continue 81 | } 82 | ret.Sin = value * 4 * 1024 83 | case "pswpout": 84 | value, err := strconv.ParseUint(fields[1], 10, 64) 85 | if err != nil { 86 | continue 87 | } 88 | ret.Sout = value * 4 * 1024 89 | } 90 | } 91 | return ret, nil 92 | } 93 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu.go: -------------------------------------------------------------------------------- 1 | package cpu 2 | 3 | import ( 4 | "encoding/json" 5 | "runtime" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | type CPUTimesStat struct { 11 | CPU string `json:"cpu"` 12 | User float64 `json:"user"` 13 | System float64 `json:"system"` 14 | Idle float64 `json:"idle"` 15 | Nice float64 `json:"nice"` 16 | Iowait float64 `json:"iowait"` 17 | Irq float64 `json:"irq"` 18 | Softirq float64 `json:"softirq"` 19 | Steal float64 `json:"steal"` 20 | Guest float64 `json:"guest"` 21 | GuestNice float64 `json:"guest_nice"` 22 | Stolen float64 `json:"stolen"` 23 | } 24 | 25 | type CPUInfoStat struct { 26 | CPU int32 `json:"cpu"` 27 | VendorID string `json:"vendor_id"` 28 | Family string `json:"family"` 29 | Model string `json:"model"` 30 | Stepping int32 `json:"stepping"` 31 | PhysicalID string `json:"physical_id"` 32 | CoreID string `json:"core_id"` 33 | Cores int32 `json:"cores"` 34 | ModelName string `json:"model_name"` 35 | Mhz float64 `json:"mhz"` 36 | CacheSize int32 `json:"cache_size"` 37 | Flags []string `json:"flags"` 38 | } 39 | 40 | var lastCPUTimes []CPUTimesStat 41 | var lastPerCPUTimes []CPUTimesStat 42 | 43 | func CPUCounts(logical bool) (int, error) { 44 | return runtime.NumCPU(), nil 45 | } 46 | 47 | func (c CPUTimesStat) String() string { 48 | v := []string{ 49 | `"cpu":"` + c.CPU + `"`, 50 | `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64), 51 | `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64), 52 | `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64), 53 | `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64), 54 | `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64), 55 | `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64), 56 | `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64), 57 | `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64), 58 | `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64), 59 | `"guest_nice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64), 60 | `"stolen":` + strconv.FormatFloat(c.Stolen, 'f', 1, 64), 61 | } 62 | 63 | return `{` + strings.Join(v, ",") + `}` 64 | } 65 | 66 | func (c CPUInfoStat) String() string { 67 | s, _ := json.Marshal(c) 68 | return string(s) 69 | } 70 | 71 | func init() { 72 | lastCPUTimes, _ = CPUTimes(false) 73 | lastPerCPUTimes, _ = CPUTimes(true) 74 | } 75 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu_test.go: -------------------------------------------------------------------------------- 1 | package cpu 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestCpu_times(t *testing.T) { 11 | v, err := CPUTimes(false) 12 | if err != nil { 13 | t.Errorf("error %v", err) 14 | } 15 | if len(v) == 0 { 16 | t.Error("could not get CPUs ", err) 17 | } 18 | empty := CPUTimesStat{} 19 | for _, vv := range v { 20 | if vv == empty { 21 | t.Errorf("could not get CPU User: %v", vv) 22 | } 23 | } 24 | } 25 | 26 | func TestCpu_counts(t *testing.T) { 27 | v, err := CPUCounts(true) 28 | if err != nil { 29 | t.Errorf("error %v", err) 30 | } 31 | if v == 0 { 32 | t.Errorf("could not get CPU counts: %v", v) 33 | } 34 | } 35 | 36 | func TestCPUTimeStat_String(t *testing.T) { 37 | v := CPUTimesStat{ 38 | CPU: "cpu0", 39 | User: 100.1, 40 | System: 200.1, 41 | Idle: 300.1, 42 | } 43 | e := `{"cpu":"cpu0","user":100.1,"system":200.1,"idle":300.1,"nice":0.0,"iowait":0.0,"irq":0.0,"softirq":0.0,"steal":0.0,"guest":0.0,"guest_nice":0.0,"stolen":0.0}` 44 | if e != fmt.Sprintf("%v", v) { 45 | t.Errorf("CPUTimesStat string is invalid: %v", v) 46 | } 47 | } 48 | 49 | func TestCpuInfo(t *testing.T) { 50 | v, err := CPUInfo() 51 | if err != nil { 52 | t.Errorf("error %v", err) 53 | } 54 | if len(v) == 0 { 55 | t.Errorf("could not get CPU Info") 56 | } 57 | for _, vv := range v { 58 | if vv.ModelName == "" { 59 | t.Errorf("could not get CPU Info: %v", vv) 60 | } 61 | } 62 | } 63 | 64 | func testCPUPercent(t *testing.T, percpu bool) { 65 | numcpu := runtime.NumCPU() 66 | testCount := 3 67 | 68 | if runtime.GOOS != "windows" { 69 | testCount = 100 70 | v, err := CPUPercent(time.Millisecond, percpu) 71 | if err != nil { 72 | t.Errorf("error %v", err) 73 | } 74 | if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { 75 | t.Fatalf("wrong number of entries from CPUPercent: %v", v) 76 | } 77 | } 78 | for i := 0; i < testCount; i++ { 79 | duration := time.Duration(10) * time.Microsecond 80 | v, err := CPUPercent(duration, percpu) 81 | if err != nil { 82 | t.Errorf("error %v", err) 83 | } 84 | for _, percent := range v { 85 | if percent < 0.0 || int(percent) > 100*numcpu { 86 | t.Fatalf("CPUPercent value is invalid: %f", percent) 87 | } 88 | } 89 | } 90 | } 91 | 92 | func TestCPUPercent(t *testing.T) { 93 | testCPUPercent(t, false) 94 | } 95 | 96 | func TestCPUPercentPerCpu(t *testing.T) { 97 | testCPUPercent(t, true) 98 | } 99 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package net 4 | 5 | import ( 6 | "strconv" 7 | "strings" 8 | 9 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 10 | ) 11 | 12 | // NetIOCounters returnes network I/O statistics for every network 13 | // interface installed on the system. If pernic argument is false, 14 | // return only sum of all information (which name is 'all'). If true, 15 | // every network interface installed on the system is returned 16 | // separately. 17 | func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { 18 | filename := "/proc/net/dev" 19 | lines, err := common.ReadLines(filename) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | statlen := len(lines) - 1 25 | 26 | ret := make([]NetIOCountersStat, 0, statlen) 27 | 28 | for _, line := range lines[2:] { 29 | parts := strings.SplitN(line, ":", 2) 30 | if len(parts) != 2 { 31 | continue 32 | } 33 | interfaceName := strings.TrimSpace(parts[0]) 34 | if interfaceName == "" { 35 | continue 36 | } 37 | 38 | fields := strings.Fields(strings.TrimSpace(parts[1])) 39 | bytesRecv, err := strconv.ParseUint(fields[0], 10, 64) 40 | if err != nil { 41 | return ret, err 42 | } 43 | packetsRecv, err := strconv.ParseUint(fields[1], 10, 64) 44 | if err != nil { 45 | return ret, err 46 | } 47 | errIn, err := strconv.ParseUint(fields[2], 10, 64) 48 | if err != nil { 49 | return ret, err 50 | } 51 | dropIn, err := strconv.ParseUint(fields[3], 10, 64) 52 | if err != nil { 53 | return ret, err 54 | } 55 | bytesSent, err := strconv.ParseUint(fields[8], 10, 64) 56 | if err != nil { 57 | return ret, err 58 | } 59 | packetsSent, err := strconv.ParseUint(fields[9], 10, 64) 60 | if err != nil { 61 | return ret, err 62 | } 63 | errOut, err := strconv.ParseUint(fields[10], 10, 64) 64 | if err != nil { 65 | return ret, err 66 | } 67 | dropOut, err := strconv.ParseUint(fields[13], 10, 64) 68 | if err != nil { 69 | return ret, err 70 | } 71 | 72 | nic := NetIOCountersStat{ 73 | Name: interfaceName, 74 | BytesRecv: bytesRecv, 75 | PacketsRecv: packetsRecv, 76 | Errin: errIn, 77 | Dropin: dropIn, 78 | BytesSent: bytesSent, 79 | PacketsSent: packetsSent, 80 | Errout: errOut, 81 | Dropout: dropOut, 82 | } 83 | ret = append(ret, nic) 84 | } 85 | 86 | if pernic == false { 87 | return getNetIOCountersAll(ret) 88 | } 89 | 90 | return ret, nil 91 | } 92 | -------------------------------------------------------------------------------- /plugins/rethinkdb/rethinkdb.go: -------------------------------------------------------------------------------- 1 | package rethinkdb 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "sync" 7 | 8 | "github.com/influxdb/telegraf/plugins" 9 | 10 | "gopkg.in/dancannon/gorethink.v1" 11 | ) 12 | 13 | type RethinkDB struct { 14 | Servers []string 15 | } 16 | 17 | var sampleConfig = ` 18 | # An array of URI to gather stats about. Specify an ip or hostname 19 | # with optional port add password. ie rethinkdb://user:auth_key@10.10.3.30:28105, 20 | # rethinkdb://10.10.3.33:18832, 10.0.0.1:10000, etc. 21 | # 22 | # If no servers are specified, then 127.0.0.1 is used as the host and 28015 as the port. 23 | servers = ["127.0.0.1:28015"]` 24 | 25 | func (r *RethinkDB) SampleConfig() string { 26 | return sampleConfig 27 | } 28 | 29 | func (r *RethinkDB) Description() string { 30 | return "Read metrics from one or many RethinkDB servers" 31 | } 32 | 33 | var localhost = &Server{Url: &url.URL{Host: "127.0.0.1:28015"}} 34 | 35 | // Reads stats from all configured servers accumulates stats. 36 | // Returns one of the errors encountered while gather stats (if any). 37 | func (r *RethinkDB) Gather(acc plugins.Accumulator) error { 38 | if len(r.Servers) == 0 { 39 | r.gatherServer(localhost, acc) 40 | return nil 41 | } 42 | 43 | var wg sync.WaitGroup 44 | 45 | var outerr error 46 | 47 | for _, serv := range r.Servers { 48 | u, err := url.Parse(serv) 49 | if err != nil { 50 | return fmt.Errorf("Unable to parse to address '%s': %s", serv, err) 51 | } else if u.Scheme == "" { 52 | // fallback to simple string based address (i.e. "10.0.0.1:10000") 53 | u.Host = serv 54 | } 55 | wg.Add(1) 56 | go func(serv string) { 57 | defer wg.Done() 58 | outerr = r.gatherServer(&Server{Url: u}, acc) 59 | }(serv) 60 | } 61 | 62 | wg.Wait() 63 | 64 | return outerr 65 | } 66 | 67 | func (r *RethinkDB) gatherServer(server *Server, acc plugins.Accumulator) error { 68 | var err error 69 | connectOpts := gorethink.ConnectOpts{ 70 | Address: server.Url.Host, 71 | DiscoverHosts: false, 72 | } 73 | if server.Url.User != nil { 74 | pwd, set := server.Url.User.Password() 75 | if set && pwd != "" { 76 | connectOpts.AuthKey = pwd 77 | } 78 | } 79 | server.session, err = gorethink.Connect(connectOpts) 80 | if err != nil { 81 | return fmt.Errorf("Unable to connect to RethinkDB, %s\n", err.Error()) 82 | } 83 | defer server.session.Close() 84 | 85 | return server.gatherData(acc) 86 | } 87 | 88 | func init() { 89 | plugins.Add("rethinkdb", func() plugins.Plugin { 90 | return &RethinkDB{} 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_posix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd darwin 2 | 3 | package process 4 | 5 | import ( 6 | "os" 7 | "os/exec" 8 | "os/user" 9 | "strconv" 10 | "strings" 11 | "syscall" 12 | ) 13 | 14 | // POSIX 15 | func getTerminalMap() (map[uint64]string, error) { 16 | ret := make(map[uint64]string) 17 | var termfiles []string 18 | 19 | d, err := os.Open("/dev") 20 | if err != nil { 21 | return nil, err 22 | } 23 | defer d.Close() 24 | 25 | devnames, err := d.Readdirnames(-1) 26 | for _, devname := range devnames { 27 | if strings.HasPrefix(devname, "/dev/tty") { 28 | termfiles = append(termfiles, "/dev/tty/"+devname) 29 | } 30 | } 31 | 32 | ptsd, err := os.Open("/dev/pts") 33 | if err != nil { 34 | return nil, err 35 | } 36 | defer ptsd.Close() 37 | 38 | ptsnames, err := ptsd.Readdirnames(-1) 39 | for _, ptsname := range ptsnames { 40 | termfiles = append(termfiles, "/dev/pts/"+ptsname) 41 | } 42 | 43 | for _, name := range termfiles { 44 | stat := syscall.Stat_t{} 45 | if err = syscall.Stat(name, &stat); err != nil { 46 | return nil, err 47 | } 48 | rdev := uint64(stat.Rdev) 49 | ret[rdev] = strings.Replace(name, "/dev", "", -1) 50 | } 51 | return ret, nil 52 | } 53 | 54 | func (p *Process) SendSignal(sig syscall.Signal) error { 55 | sigAsStr := "INT" 56 | switch sig { 57 | case syscall.SIGSTOP: 58 | sigAsStr = "STOP" 59 | case syscall.SIGCONT: 60 | sigAsStr = "CONT" 61 | case syscall.SIGTERM: 62 | sigAsStr = "TERM" 63 | case syscall.SIGKILL: 64 | sigAsStr = "KILL" 65 | } 66 | 67 | cmd := exec.Command("kill", "-s", sigAsStr, strconv.Itoa(int(p.Pid))) 68 | cmd.Stderr = os.Stderr 69 | err := cmd.Run() 70 | if err != nil { 71 | return err 72 | } 73 | 74 | return nil 75 | } 76 | 77 | func (p *Process) Suspend() error { 78 | return p.SendSignal(syscall.SIGSTOP) 79 | } 80 | func (p *Process) Resume() error { 81 | return p.SendSignal(syscall.SIGCONT) 82 | } 83 | func (p *Process) Terminate() error { 84 | return p.SendSignal(syscall.SIGTERM) 85 | } 86 | func (p *Process) Kill() error { 87 | return p.SendSignal(syscall.SIGKILL) 88 | } 89 | func (p *Process) Username() (string, error) { 90 | uids, err := p.Uids() 91 | if err != nil { 92 | return "", err 93 | } 94 | if len(uids) > 0 { 95 | u, err := user.LookupId(strconv.Itoa(int(uids[0]))) 96 | if err != nil { 97 | return "", err 98 | } 99 | return u.Username, nil 100 | } 101 | return "", nil 102 | } 103 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_freebsd_386.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | // +build 386 3 | 4 | package process 5 | 6 | // copied from sys/sysctl.h 7 | const ( 8 | CTLKern = 1 // "high kernel": proc, limits 9 | KernProc = 14 // struct: process entries 10 | KernProcPID = 1 // by process id 11 | KernProcProc = 8 // only return procs 12 | KernProcPathname = 12 // path to executable 13 | ) 14 | 15 | // copied from sys/user.h 16 | type KinfoProc struct { 17 | KiStructsize int32 18 | KiLayout int32 19 | KiArgs int32 20 | KiPaddr int32 21 | KiAddr int32 22 | KiTracep int32 23 | KiTextvp int32 24 | KiFd int32 25 | KiVmspace int32 26 | KiWchan int32 27 | KiPid int32 28 | KiPpid int32 29 | KiPgid int32 30 | KiTpgid int32 31 | KiSid int32 32 | KiTsid int32 33 | KiJobc [2]byte 34 | KiSpareShort1 [2]byte 35 | KiTdev int32 36 | KiSiglist [16]byte 37 | KiSigmask [16]byte 38 | KiSigignore [16]byte 39 | KiSigcatch [16]byte 40 | KiUID int32 41 | KiRuid int32 42 | KiSvuid int32 43 | KiRgid int32 44 | KiSvgid int32 45 | KiNgroups [2]byte 46 | KiSpareShort2 [2]byte 47 | KiGroups [64]byte 48 | KiSize int32 49 | KiRssize int32 50 | KiSwrss int32 51 | KiTsize int32 52 | KiDsize int32 53 | KiSsize int32 54 | KiXstat [2]byte 55 | KiAcflag [2]byte 56 | KiPctcpu int32 57 | KiEstcpu int32 58 | KiSlptime int32 59 | KiSwtime int32 60 | KiCow int32 61 | KiRuntime int64 62 | KiStart [8]byte 63 | KiChildtime [8]byte 64 | KiFlag int32 65 | KiKflag int32 66 | KiTraceflag int32 67 | KiStat [1]byte 68 | KiNice [1]byte 69 | KiLock [1]byte 70 | KiRqindex [1]byte 71 | KiOncpu [1]byte 72 | KiLastcpu [1]byte 73 | KiOcomm [17]byte 74 | KiWmesg [9]byte 75 | KiLogin [18]byte 76 | KiLockname [9]byte 77 | KiComm [20]byte 78 | KiEmul [17]byte 79 | KiSparestrings [68]byte 80 | KiSpareints [36]byte 81 | KiCrFlags int32 82 | KiJid int32 83 | KiNumthreads int32 84 | KiTid int32 85 | KiPri int32 86 | KiRusage [72]byte 87 | KiRusageCh [72]byte 88 | KiPcb int32 89 | KiKstack int32 90 | KiUdata int32 91 | KiTdaddr int32 92 | KiSpareptrs [24]byte 93 | KiSpareint64s [48]byte 94 | KiSflag int32 95 | KiTdflags int32 96 | } 97 | -------------------------------------------------------------------------------- /plugins/rethinkdb/rethinkdb_data_test.go: -------------------------------------------------------------------------------- 1 | package rethinkdb 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/influxdb/telegraf/testutil" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var tags = make(map[string]string) 11 | 12 | func TestAddEngineStats(t *testing.T) { 13 | engine := &Engine{ 14 | ClientConns: 0, 15 | ClientActive: 0, 16 | QueriesPerSec: 0, 17 | TotalQueries: 0, 18 | ReadsPerSec: 0, 19 | TotalReads: 0, 20 | WritesPerSec: 0, 21 | TotalWrites: 0, 22 | } 23 | 24 | var acc testutil.Accumulator 25 | 26 | keys := []string{ 27 | "active_clients", 28 | "clients", 29 | "queries_per_sec", 30 | "total_queries", 31 | "read_docs_per_sec", 32 | "total_reads", 33 | "written_docs_per_sec", 34 | "total_writes", 35 | } 36 | engine.AddEngineStats(keys, &acc, tags) 37 | 38 | for _, metric := range keys { 39 | assert.True(t, acc.HasIntValue(metric)) 40 | } 41 | } 42 | 43 | func TestAddEngineStatsPartial(t *testing.T) { 44 | engine := &Engine{ 45 | ClientConns: 0, 46 | ClientActive: 0, 47 | QueriesPerSec: 0, 48 | ReadsPerSec: 0, 49 | WritesPerSec: 0, 50 | } 51 | 52 | var acc testutil.Accumulator 53 | 54 | keys := []string{ 55 | "active_clients", 56 | "clients", 57 | "queries_per_sec", 58 | "read_docs_per_sec", 59 | "written_docs_per_sec", 60 | } 61 | 62 | missing_keys := []string{ 63 | "total_queries", 64 | "total_reads", 65 | "total_writes", 66 | } 67 | engine.AddEngineStats(keys, &acc, tags) 68 | 69 | for _, metric := range missing_keys { 70 | assert.False(t, acc.HasIntValue(metric)) 71 | } 72 | } 73 | 74 | func TestAddStorageStats(t *testing.T) { 75 | storage := &Storage{ 76 | Cache: Cache{ 77 | BytesInUse: 0, 78 | }, 79 | Disk: Disk{ 80 | ReadBytesPerSec: 0, 81 | ReadBytesTotal: 0, 82 | WriteBytesPerSec: 0, 83 | WriteBytesTotal: 0, 84 | SpaceUsage: SpaceUsage{ 85 | Data: 0, 86 | Garbage: 0, 87 | Metadata: 0, 88 | Prealloc: 0, 89 | }, 90 | }, 91 | } 92 | 93 | var acc testutil.Accumulator 94 | 95 | keys := []string{ 96 | "cache_bytes_in_use", 97 | "disk_read_bytes_per_sec", 98 | "disk_read_bytes_total", 99 | "disk_written_bytes_per_sec", 100 | "disk_written_bytes_total", 101 | "disk_usage_data_bytes", 102 | "disk_usage_garbage_bytes", 103 | "disk_usage_metadata_bytes", 104 | "disk_usage_preallocated_bytes", 105 | } 106 | 107 | storage.AddStats(&acc, tags) 108 | 109 | for _, metric := range keys { 110 | assert.True(t, acc.HasIntValue(metric)) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_freebsd_amd64.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | // +build amd64 3 | 4 | package process 5 | 6 | // copied from sys/sysctl.h 7 | const ( 8 | CTLKern = 1 // "high kernel": proc, limits 9 | KernProc = 14 // struct: process entries 10 | KernProcPID = 1 // by process id 11 | KernProcProc = 8 // only return procs 12 | KernProcPathname = 12 // path to executable 13 | ) 14 | 15 | // copied from sys/user.h 16 | type KinfoProc struct { 17 | KiStructsize int32 18 | KiLayout int32 19 | KiArgs int64 20 | KiPaddr int64 21 | KiAddr int64 22 | KiTracep int64 23 | KiTextvp int64 24 | KiFd int64 25 | KiVmspace int64 26 | KiWchan int64 27 | KiPid int32 28 | KiPpid int32 29 | KiPgid int32 30 | KiTpgid int32 31 | KiSid int32 32 | KiTsid int32 33 | KiJobc [2]byte 34 | KiSpareShort1 [2]byte 35 | KiTdev int32 36 | KiSiglist [16]byte 37 | KiSigmask [16]byte 38 | KiSigignore [16]byte 39 | KiSigcatch [16]byte 40 | KiUID int32 41 | KiRuid int32 42 | KiSvuid int32 43 | KiRgid int32 44 | KiSvgid int32 45 | KiNgroups [2]byte 46 | KiSpareShort2 [2]byte 47 | KiGroups [64]byte 48 | KiSize int64 49 | KiRssize int64 50 | KiSwrss int64 51 | KiTsize int64 52 | KiDsize int64 53 | KiSsize int64 54 | KiXstat [2]byte 55 | KiAcflag [2]byte 56 | KiPctcpu int32 57 | KiEstcpu int32 58 | KiSlptime int32 59 | KiSwtime int32 60 | KiCow int32 61 | KiRuntime int64 62 | KiStart [16]byte 63 | KiChildtime [16]byte 64 | KiFlag int64 65 | KiKflag int64 66 | KiTraceflag int32 67 | KiStat [1]byte 68 | KiNice [1]byte 69 | KiLock [1]byte 70 | KiRqindex [1]byte 71 | KiOncpu [1]byte 72 | KiLastcpu [1]byte 73 | KiOcomm [17]byte 74 | KiWmesg [9]byte 75 | KiLogin [18]byte 76 | KiLockname [9]byte 77 | KiComm [20]byte 78 | KiEmul [17]byte 79 | KiSparestrings [68]byte 80 | KiSpareints [36]byte 81 | KiCrFlags int32 82 | KiJid int32 83 | KiNumthreads int32 84 | KiTid int32 85 | KiPri int32 86 | KiRusage [144]byte 87 | KiRusageCh [144]byte 88 | KiPcb int64 89 | KiKstack int64 90 | KiUdata int64 91 | KiTdaddr int64 92 | KiSpareptrs [48]byte 93 | KiSpareint64s [96]byte 94 | KiSflag int64 95 | KiTdflags int64 96 | } 97 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package disk 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | "github.com/influxdb/telegraf/plugins/system/ps/common" 10 | ) 11 | 12 | func DiskPartitions(all bool) ([]DiskPartitionStat, error) { 13 | var ret []DiskPartitionStat 14 | 15 | count, err := Getfsstat(nil, MntWait) 16 | if err != nil { 17 | return ret, err 18 | } 19 | fs := make([]Statfs_t, count) 20 | _, err = Getfsstat(fs, MntWait) 21 | for _, stat := range fs { 22 | opts := "rw" 23 | if stat.Flags&MntReadOnly != 0 { 24 | opts = "ro" 25 | } 26 | if stat.Flags&MntSynchronous != 0 { 27 | opts += ",sync" 28 | } 29 | if stat.Flags&MntNoExec != 0 { 30 | opts += ",noexec" 31 | } 32 | if stat.Flags&MntNoSuid != 0 { 33 | opts += ",nosuid" 34 | } 35 | if stat.Flags&MntUnion != 0 { 36 | opts += ",union" 37 | } 38 | if stat.Flags&MntAsync != 0 { 39 | opts += ",async" 40 | } 41 | if stat.Flags&MntSuidDir != 0 { 42 | opts += ",suiddir" 43 | } 44 | if stat.Flags&MntSoftDep != 0 { 45 | opts += ",softdep" 46 | } 47 | if stat.Flags&MntNoSymFollow != 0 { 48 | opts += ",nosymfollow" 49 | } 50 | if stat.Flags&MntGEOMJournal != 0 { 51 | opts += ",gjounalc" 52 | } 53 | if stat.Flags&MntMultilabel != 0 { 54 | opts += ",multilabel" 55 | } 56 | if stat.Flags&MntACLs != 0 { 57 | opts += ",acls" 58 | } 59 | if stat.Flags&MntNoATime != 0 { 60 | opts += ",noattime" 61 | } 62 | if stat.Flags&MntClusterRead != 0 { 63 | opts += ",nocluster" 64 | } 65 | if stat.Flags&MntClusterWrite != 0 { 66 | opts += ",noclusterw" 67 | } 68 | if stat.Flags&MntNFS4ACLs != 0 { 69 | opts += ",nfs4acls" 70 | } 71 | d := DiskPartitionStat{ 72 | Device: common.IntToString(stat.Mntfromname[:]), 73 | Mountpoint: common.IntToString(stat.Mntonname[:]), 74 | Fstype: common.IntToString(stat.Fstypename[:]), 75 | Opts: opts, 76 | } 77 | ret = append(ret, d) 78 | } 79 | 80 | return ret, nil 81 | } 82 | 83 | func DiskIOCounters() (map[string]DiskIOCountersStat, error) { 84 | return nil, common.NotImplementedError 85 | } 86 | 87 | func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { 88 | var _p0 unsafe.Pointer 89 | var bufsize uintptr 90 | if len(buf) > 0 { 91 | _p0 = unsafe.Pointer(&buf[0]) 92 | bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) 93 | } 94 | r0, _, e1 := syscall.Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags)) 95 | n = int(r0) 96 | if e1 != 0 { 97 | err = e1 98 | } 99 | return 100 | } 101 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package net 4 | 5 | import ( 6 | "net" 7 | "os" 8 | "syscall" 9 | "unsafe" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | ) 13 | 14 | var ( 15 | modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") 16 | procGetExtendedTcpTable = modiphlpapi.NewProc("GetExtendedTcpTable") 17 | procGetExtendedUdpTable = modiphlpapi.NewProc("GetExtendedUdpTable") 18 | ) 19 | 20 | const ( 21 | TCPTableBasicListener = iota 22 | TCPTableBasicConnections 23 | TCPTableBasicAll 24 | TCPTableOwnerPIDListener 25 | TCPTableOwnerPIDConnections 26 | TCPTableOwnerPIDAll 27 | TCPTableOwnerModuleListener 28 | TCPTableOwnerModuleConnections 29 | TCPTableOwnerModuleAll 30 | ) 31 | 32 | func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { 33 | ifs, err := net.Interfaces() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | ai, err := getAdapterList() 39 | if err != nil { 40 | return nil, err 41 | } 42 | var ret []NetIOCountersStat 43 | 44 | for _, ifi := range ifs { 45 | name := ifi.Name 46 | for ; ai != nil; ai = ai.Next { 47 | name = common.BytePtrToString(&ai.Description[0]) 48 | c := NetIOCountersStat{ 49 | Name: name, 50 | } 51 | 52 | row := syscall.MibIfRow{Index: ai.Index} 53 | e := syscall.GetIfEntry(&row) 54 | if e != nil { 55 | return nil, os.NewSyscallError("GetIfEntry", e) 56 | } 57 | c.BytesSent = uint64(row.OutOctets) 58 | c.BytesRecv = uint64(row.InOctets) 59 | c.PacketsSent = uint64(row.OutUcastPkts) 60 | c.PacketsRecv = uint64(row.InUcastPkts) 61 | c.Errin = uint64(row.InErrors) 62 | c.Errout = uint64(row.OutErrors) 63 | c.Dropin = uint64(row.InDiscards) 64 | c.Dropout = uint64(row.OutDiscards) 65 | 66 | ret = append(ret, c) 67 | } 68 | } 69 | 70 | if pernic == false { 71 | return getNetIOCountersAll(ret) 72 | } 73 | return ret, nil 74 | } 75 | 76 | // Return a list of network connections opened by a process 77 | func NetConnections(kind string) ([]NetConnectionStat, error) { 78 | var ret []NetConnectionStat 79 | 80 | return ret, common.NotImplementedError 81 | } 82 | 83 | // borrowed from src/pkg/net/interface_windows.go 84 | func getAdapterList() (*syscall.IpAdapterInfo, error) { 85 | b := make([]byte, 1000) 86 | l := uint32(len(b)) 87 | a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) 88 | err := syscall.GetAdaptersInfo(a, &l) 89 | if err == syscall.ERROR_BUFFER_OVERFLOW { 90 | b = make([]byte, l) 91 | a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) 92 | err = syscall.GetAdaptersInfo(a, &l) 93 | } 94 | if err != nil { 95 | return nil, os.NewSyscallError("GetAdaptersInfo", err) 96 | } 97 | return a, nil 98 | } 99 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/types_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // Hand writing: _Ctype_struct___0 3 | 4 | /* 5 | Input to cgo -godefs. 6 | 7 | */ 8 | 9 | package disk 10 | 11 | /* 12 | #include 13 | #include 14 | #include 15 | 16 | enum { 17 | sizeofPtr = sizeof(void*), 18 | }; 19 | 20 | // because statinfo has long double snap_time, redefine with changing long long 21 | struct statinfo2 { 22 | long cp_time[CPUSTATES]; 23 | long tk_nin; 24 | long tk_nout; 25 | struct devinfo *dinfo; 26 | long long snap_time; 27 | }; 28 | */ 29 | import "C" 30 | 31 | // Machine characteristics; for internal use. 32 | 33 | const ( 34 | sizeofPtr = C.sizeofPtr 35 | sizeofShort = C.sizeof_short 36 | sizeofInt = C.sizeof_int 37 | sizeofLong = C.sizeof_long 38 | sizeofLongLong = C.sizeof_longlong 39 | sizeofLongDouble = C.sizeof_longlong 40 | 41 | DEVSTAT_NO_DATA = 0x00 42 | DEVSTAT_READ = 0x01 43 | DEVSTAT_WRITE = 0x02 44 | DEVSTAT_FREE = 0x03 45 | 46 | // from sys/mount.h 47 | MNT_RDONLY = 0x00000001 /* read only filesystem */ 48 | MNT_SYNCHRONOUS = 0x00000002 /* filesystem written synchronously */ 49 | MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */ 50 | MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */ 51 | MNT_UNION = 0x00000020 /* union with underlying filesystem */ 52 | MNT_ASYNC = 0x00000040 /* filesystem written asynchronously */ 53 | MNT_SUIDDIR = 0x00100000 /* special handling of SUID on dirs */ 54 | MNT_SOFTDEP = 0x00200000 /* soft updates being done */ 55 | MNT_NOSYMFOLLOW = 0x00400000 /* do not follow symlinks */ 56 | MNT_GJOURNAL = 0x02000000 /* GEOM journal support enabled */ 57 | MNT_MULTILABEL = 0x04000000 /* MAC support for individual objects */ 58 | MNT_ACLS = 0x08000000 /* ACL support enabled */ 59 | MNT_NOATIME = 0x10000000 /* disable update of file access time */ 60 | MNT_NOCLUSTERR = 0x40000000 /* disable cluster read */ 61 | MNT_NOCLUSTERW = 0x80000000 /* disable cluster write */ 62 | MNT_NFS4ACLS = 0x00000010 63 | 64 | MNT_WAIT = 1 /* synchronously wait for I/O to complete */ 65 | MNT_NOWAIT = 2 /* start all I/O, but do not wait for it */ 66 | MNT_LAZY = 3 /* push data not written by filesystem syncer */ 67 | MNT_SUSPEND = 4 /* Suspend file system after sync */ 68 | 69 | ) 70 | 71 | // Basic types 72 | 73 | type ( 74 | _C_short C.short 75 | _C_int C.int 76 | _C_long C.long 77 | _C_long_long C.longlong 78 | _C_long_double C.longlong 79 | ) 80 | 81 | type Statfs C.struct_statfs 82 | type Fsid C.struct_fsid 83 | 84 | type Devstat C.struct_devstat 85 | type Bintime C.struct_bintime 86 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package mem 4 | 5 | import ( 6 | "os/exec" 7 | "strconv" 8 | "strings" 9 | 10 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 11 | ) 12 | 13 | func getPageSize() (uint64, error) { 14 | out, err := exec.Command("pagesize").Output() 15 | if err != nil { 16 | return 0, err 17 | } 18 | o := strings.TrimSpace(string(out)) 19 | p, err := strconv.ParseUint(o, 10, 64) 20 | if err != nil { 21 | return 0, err 22 | } 23 | 24 | return p, nil 25 | } 26 | 27 | // VirtualMemory returns VirtualmemoryStat. 28 | func VirtualMemory() (*VirtualMemoryStat, error) { 29 | p, err := getPageSize() 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | total, err := common.DoSysctrl("hw.memsize") 35 | if err != nil { 36 | return nil, err 37 | } 38 | free, err := common.DoSysctrl("vm.page_free_count") 39 | if err != nil { 40 | return nil, err 41 | } 42 | parsed := make([]uint64, 0, 7) 43 | vv := []string{ 44 | total[0], 45 | free[0], 46 | } 47 | for _, target := range vv { 48 | t, err := strconv.ParseUint(target, 10, 64) 49 | if err != nil { 50 | return nil, err 51 | } 52 | parsed = append(parsed, t) 53 | } 54 | 55 | ret := &VirtualMemoryStat{ 56 | Total: parsed[0] * p, 57 | Free: parsed[1] * p, 58 | } 59 | 60 | // TODO: platform independent (worked freebsd?) 61 | ret.Available = ret.Free + ret.Buffers + ret.Cached 62 | 63 | ret.Used = ret.Total - ret.Free 64 | ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 65 | 66 | return ret, nil 67 | } 68 | 69 | // SwapMemory returns swapinfo. 70 | func SwapMemory() (*SwapMemoryStat, error) { 71 | var ret *SwapMemoryStat 72 | 73 | swapUsage, err := common.DoSysctrl("vm.swapusage") 74 | if err != nil { 75 | return ret, err 76 | } 77 | 78 | total := strings.Replace(swapUsage[2], "M", "", 1) 79 | used := strings.Replace(swapUsage[5], "M", "", 1) 80 | free := strings.Replace(swapUsage[8], "M", "", 1) 81 | 82 | total_v, err := strconv.ParseFloat(total, 64) 83 | if err != nil { 84 | return nil, err 85 | } 86 | used_v, err := strconv.ParseFloat(used, 64) 87 | if err != nil { 88 | return nil, err 89 | } 90 | free_v, err := strconv.ParseFloat(free, 64) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | u := float64(0) 96 | if total_v != 0 { 97 | u = ((total_v - free_v) / total_v) * 100.0 98 | } 99 | 100 | // vm.swapusage shows "M", multiply 1000 101 | ret = &SwapMemoryStat{ 102 | Total: uint64(total_v * 1000), 103 | Used: uint64(used_v * 1000), 104 | Free: uint64(free_v * 1000), 105 | UsedPercent: u, 106 | } 107 | 108 | return ret, nil 109 | } 110 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_freebsd_amd64.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs types_freebsd.go 3 | 4 | package disk 5 | 6 | const ( 7 | sizeofPtr = 0x8 8 | sizeofShort = 0x2 9 | sizeofInt = 0x4 10 | sizeofLong = 0x8 11 | sizeofLongLong = 0x8 12 | sizeofLongDouble = 0x8 13 | 14 | DEVSTAT_NO_DATA = 0x00 15 | DEVSTAT_READ = 0x01 16 | DEVSTAT_WRITE = 0x02 17 | DEVSTAT_FREE = 0x03 18 | 19 | MNT_RDONLY = 0x00000001 20 | MNT_SYNCHRONOUS = 0x00000002 21 | MNT_NOEXEC = 0x00000004 22 | MNT_NOSUID = 0x00000008 23 | MNT_UNION = 0x00000020 24 | MNT_ASYNC = 0x00000040 25 | MNT_SUIDDIR = 0x00100000 26 | MNT_SOFTDEP = 0x00200000 27 | MNT_NOSYMFOLLOW = 0x00400000 28 | MNT_GJOURNAL = 0x02000000 29 | MNT_MULTILABEL = 0x04000000 30 | MNT_ACLS = 0x08000000 31 | MNT_NOATIME = 0x10000000 32 | MNT_NOCLUSTERR = 0x40000000 33 | MNT_NOCLUSTERW = 0x80000000 34 | MNT_NFS4ACLS = 0x00000010 35 | 36 | MNT_WAIT = 1 37 | MNT_NOWAIT = 2 38 | MNT_LAZY = 3 39 | MNT_SUSPEND = 4 40 | ) 41 | 42 | type ( 43 | _C_short int16 44 | _C_int int32 45 | _C_long int64 46 | _C_long_long int64 47 | _C_long_double int64 48 | ) 49 | 50 | type Statfs struct { 51 | Version uint32 52 | Type uint32 53 | Flags uint64 54 | Bsize uint64 55 | Iosize uint64 56 | Blocks uint64 57 | Bfree uint64 58 | Bavail int64 59 | Files uint64 60 | Ffree int64 61 | Syncwrites uint64 62 | Asyncwrites uint64 63 | Syncreads uint64 64 | Asyncreads uint64 65 | Spare [10]uint64 66 | Namemax uint32 67 | Owner uint32 68 | Fsid Fsid 69 | Charspare [80]int8 70 | Fstypename [16]int8 71 | Mntfromname [88]int8 72 | Mntonname [88]int8 73 | } 74 | type Fsid struct { 75 | Val [2]int32 76 | } 77 | 78 | type Devstat struct { 79 | Sequence0 uint32 80 | Allocated int32 81 | Start_count uint32 82 | End_count uint32 83 | Busy_from Bintime 84 | Dev_links _Ctype_struct___0 85 | Device_number uint32 86 | Device_name [16]int8 87 | Unit_number int32 88 | Bytes [4]uint64 89 | Operations [4]uint64 90 | Duration [4]Bintime 91 | Busy_time Bintime 92 | Creation_time Bintime 93 | Block_size uint32 94 | Pad_cgo_0 [4]byte 95 | Tag_types [3]uint64 96 | Flags uint32 97 | Device_type uint32 98 | Priority uint32 99 | Pad_cgo_1 [4]byte 100 | Id *byte 101 | Sequence1 uint32 102 | Pad_cgo_2 [4]byte 103 | } 104 | type Bintime struct { 105 | Sec int64 106 | Frac uint64 107 | } 108 | 109 | type _Ctype_struct___0 struct { 110 | Empty uint64 111 | } 112 | -------------------------------------------------------------------------------- /plugins/kafka_consumer/kafka_consumer_test.go: -------------------------------------------------------------------------------- 1 | package kafka_consumer 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | "time" 7 | 8 | "github.com/influxdb/telegraf/testutil" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | "gopkg.in/Shopify/sarama.v1" 12 | ) 13 | 14 | const testMsg = "cpu_load_short,direction=in,host=server01,region=us-west value=23422.0 1422568543702900257" 15 | 16 | func TestReadFromKafkaBatchesMsgsOnBatchSize(t *testing.T) { 17 | halt := make(chan bool, 1) 18 | metricChan := make(chan []byte, 1) 19 | kafkaChan := make(chan *sarama.ConsumerMessage, 10) 20 | for i := 0; i < 10; i++ { 21 | kafkaChan <- saramaMsg(testMsg) 22 | } 23 | 24 | expectedBatch := strings.Repeat(testMsg+"\n", 9) + testMsg 25 | readFromKafka(kafkaChan, metricChan, 10, func(msg *sarama.ConsumerMessage) error { 26 | batch := <-metricChan 27 | assert.Equal(t, expectedBatch, string(batch)) 28 | 29 | halt <- true 30 | 31 | return nil 32 | }, halt) 33 | } 34 | 35 | func TestReadFromKafkaBatchesMsgsOnTimeout(t *testing.T) { 36 | halt := make(chan bool, 1) 37 | metricChan := make(chan []byte, 1) 38 | kafkaChan := make(chan *sarama.ConsumerMessage, 10) 39 | for i := 0; i < 3; i++ { 40 | kafkaChan <- saramaMsg(testMsg) 41 | } 42 | 43 | expectedBatch := strings.Repeat(testMsg+"\n", 2) + testMsg 44 | readFromKafka(kafkaChan, metricChan, 10, func(msg *sarama.ConsumerMessage) error { 45 | batch := <-metricChan 46 | assert.Equal(t, expectedBatch, string(batch)) 47 | 48 | halt <- true 49 | 50 | return nil 51 | }, halt) 52 | } 53 | 54 | func TestEmitMetricsSendMetricsToAcc(t *testing.T) { 55 | k := &Kafka{} 56 | var acc testutil.Accumulator 57 | testChan := make(chan []byte, 1) 58 | testChan <- []byte(testMsg) 59 | 60 | err := emitMetrics(k, &acc, testChan) 61 | require.NoError(t, err) 62 | 63 | assert.Equal(t, 1, len(acc.Points), "there should be a single point") 64 | 65 | point := acc.Points[0] 66 | assert.Equal(t, "cpu_load_short", point.Measurement) 67 | assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Values) 68 | assert.Equal(t, map[string]string{ 69 | "host": "server01", 70 | "direction": "in", 71 | "region": "us-west", 72 | }, point.Tags) 73 | 74 | assert.Equal(t, time.Unix(0, 1422568543702900257), point.Time) 75 | } 76 | 77 | func TestEmitMetricsTimesOut(t *testing.T) { 78 | k := &Kafka{} 79 | var acc testutil.Accumulator 80 | testChan := make(chan []byte) 81 | 82 | err := emitMetrics(k, &acc, testChan) 83 | require.NoError(t, err) 84 | 85 | assert.Equal(t, 0, len(acc.Points), "there should not be a any points") 86 | } 87 | 88 | func saramaMsg(val string) *sarama.ConsumerMessage { 89 | return &sarama.ConsumerMessage{ 90 | Key: nil, 91 | Value: []byte(val), 92 | Offset: 0, 93 | Partition: 0, 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /cmd/telegraf/telegraf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "os/signal" 9 | "strings" 10 | 11 | "github.com/influxdb/telegraf" 12 | _ "github.com/influxdb/telegraf/plugins/all" 13 | ) 14 | 15 | var fDebug = flag.Bool("debug", false, "show metrics as they're generated to stdout") 16 | var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit") 17 | var fConfig = flag.String("config", "", "configuration file to load") 18 | var fVersion = flag.Bool("version", false, "display the version") 19 | var fSampleConfig = flag.Bool("sample-config", false, "print out full sample configuration") 20 | var fPidfile = flag.String("pidfile", "", "file to write our pid to") 21 | 22 | var Version = "unreleased" 23 | var Commit = "" 24 | 25 | func main() { 26 | flag.Parse() 27 | 28 | if *fVersion { 29 | fmt.Printf("InfluxDB Telegraf agent - Version %s\n", Version) 30 | return 31 | } 32 | 33 | if *fSampleConfig { 34 | telegraf.PrintSampleConfig() 35 | return 36 | } 37 | 38 | var ( 39 | config *telegraf.Config 40 | err error 41 | ) 42 | 43 | if *fConfig != "" { 44 | config, err = telegraf.LoadConfig(*fConfig) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | } else { 49 | config = telegraf.DefaultConfig() 50 | } 51 | 52 | ag, err := telegraf.NewAgent(config) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | if *fDebug { 58 | ag.Debug = true 59 | } 60 | 61 | plugins, err := ag.LoadPlugins() 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | 66 | if *fTest { 67 | if *fConfig != "" { 68 | err = ag.Test() 69 | } else { 70 | err = ag.TestAllPlugins() 71 | } 72 | 73 | if err != nil { 74 | log.Fatal(err) 75 | } 76 | 77 | return 78 | } 79 | 80 | err = ag.Connect() 81 | if err != nil { 82 | log.Fatal(err) 83 | } 84 | 85 | shutdown := make(chan struct{}) 86 | 87 | signals := make(chan os.Signal) 88 | 89 | signal.Notify(signals, os.Interrupt) 90 | 91 | go func() { 92 | <-signals 93 | close(shutdown) 94 | }() 95 | 96 | log.Print("InfluxDB Agent running") 97 | log.Printf("Loaded plugins: %s", strings.Join(plugins, " ")) 98 | if ag.Debug { 99 | log.Printf("Debug: enabled") 100 | log.Printf("Agent Config: Interval:%s, Debug:%#v, Hostname:%#v\n", 101 | ag.Interval, ag.Debug, ag.Hostname) 102 | } 103 | 104 | if config.URL != "" { 105 | log.Printf("Sending metrics to: %s", config.URL) 106 | log.Printf("Tags enabled: %v", config.ListTags()) 107 | } 108 | 109 | if *fPidfile != "" { 110 | f, err := os.Create(*fPidfile) 111 | if err != nil { 112 | log.Fatalf("Unable to create pidfile: %s", err) 113 | } 114 | 115 | fmt.Fprintf(f, "%d\n", os.Getpid()) 116 | 117 | f.Close() 118 | } 119 | 120 | ag.Run(shutdown) 121 | } 122 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package cpu 4 | 5 | import ( 6 | "strconv" 7 | "syscall" 8 | "time" 9 | "unsafe" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | ) 13 | 14 | // TODO: Get percpu 15 | func CPUTimes(percpu bool) ([]CPUTimesStat, error) { 16 | var ret []CPUTimesStat 17 | 18 | var lpIdleTime common.FILETIME 19 | var lpKernelTime common.FILETIME 20 | var lpUserTime common.FILETIME 21 | r, _, _ := common.ProcGetSystemTimes.Call( 22 | uintptr(unsafe.Pointer(&lpIdleTime)), 23 | uintptr(unsafe.Pointer(&lpKernelTime)), 24 | uintptr(unsafe.Pointer(&lpUserTime))) 25 | if r == 0 { 26 | return ret, syscall.GetLastError() 27 | } 28 | 29 | LOT := float64(0.0000001) 30 | HIT := (LOT * 4294967296.0) 31 | idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime))) 32 | user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime))) 33 | kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime))) 34 | system := (kernel - idle) 35 | 36 | ret = append(ret, CPUTimesStat{ 37 | Idle: float64(idle), 38 | User: float64(user), 39 | System: float64(system), 40 | }) 41 | return ret, nil 42 | } 43 | 44 | func CPUInfo() ([]CPUInfoStat, error) { 45 | var ret []CPUInfoStat 46 | lines, err := common.GetWmic("cpu", "get", "Family,L2CacheSize,Manufacturer,Name,NumberOfLogicalProcessors,ProcessorId,Stepping") 47 | if err != nil { 48 | return ret, err 49 | } 50 | for i, t := range lines { 51 | cache, err := strconv.Atoi(t[2]) 52 | if err != nil { 53 | cache = 0 54 | } 55 | cores, err := strconv.Atoi(t[5]) 56 | if err != nil { 57 | cores = 0 58 | } 59 | stepping := 0 60 | if len(t) > 7 { 61 | stepping, err = strconv.Atoi(t[6]) 62 | if err != nil { 63 | stepping = 0 64 | } 65 | } 66 | cpu := CPUInfoStat{ 67 | CPU: int32(i), 68 | Family: t[1], 69 | CacheSize: int32(cache), 70 | VendorID: t[3], 71 | ModelName: t[4], 72 | Cores: int32(cores), 73 | PhysicalID: t[6], 74 | Stepping: int32(stepping), 75 | Flags: []string{}, 76 | } 77 | ret = append(ret, cpu) 78 | } 79 | return ret, nil 80 | } 81 | 82 | func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) { 83 | ret := []float64{} 84 | 85 | lines, err := common.GetWmic("cpu", "get", "loadpercentage") 86 | if err != nil { 87 | return ret, err 88 | } 89 | for _, l := range lines { 90 | if len(l) < 2 { 91 | continue 92 | } 93 | p, err := strconv.Atoi(l[1]) 94 | if err != nil { 95 | p = 0 96 | } 97 | // but windows can only get one percent. 98 | ret = append(ret, float64(p)/100.0) 99 | } 100 | return ret, nil 101 | } 102 | -------------------------------------------------------------------------------- /plugins/prometheus/prometheus.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | "sync" 8 | "time" 9 | 10 | "github.com/influxdb/telegraf/plugins" 11 | "github.com/prometheus/client_golang/extraction" 12 | "github.com/prometheus/client_golang/model" 13 | ) 14 | 15 | type Prometheus struct { 16 | Urls []string 17 | } 18 | 19 | var sampleConfig = ` 20 | # An array of urls to scrape metrics from. 21 | urls = ["http://localhost:9100/metrics"]` 22 | 23 | func (r *Prometheus) SampleConfig() string { 24 | return sampleConfig 25 | } 26 | 27 | func (r *Prometheus) Description() string { 28 | return "Read metrics from one or many prometheus clients" 29 | } 30 | 31 | var ErrProtocolError = errors.New("prometheus protocol error") 32 | 33 | // Reads stats from all configured servers accumulates stats. 34 | // Returns one of the errors encountered while gather stats (if any). 35 | func (g *Prometheus) Gather(acc plugins.Accumulator) error { 36 | var wg sync.WaitGroup 37 | 38 | var outerr error 39 | 40 | for _, serv := range g.Urls { 41 | wg.Add(1) 42 | go func(serv string) { 43 | defer wg.Done() 44 | outerr = g.gatherURL(serv, acc) 45 | }(serv) 46 | } 47 | 48 | wg.Wait() 49 | 50 | return outerr 51 | } 52 | 53 | func (g *Prometheus) gatherURL(url string, acc plugins.Accumulator) error { 54 | resp, err := http.Get(url) 55 | if err != nil { 56 | return fmt.Errorf("error making HTTP request to %s: %s", url, err) 57 | } 58 | defer resp.Body.Close() 59 | if resp.StatusCode != http.StatusOK { 60 | return fmt.Errorf("%s returned HTTP status %s", url, resp.Status) 61 | } 62 | processor, err := extraction.ProcessorForRequestHeader(resp.Header) 63 | if err != nil { 64 | return fmt.Errorf("error getting extractor for %s: %s", url, err) 65 | } 66 | 67 | ingestor := &Ingester{ 68 | acc: acc, 69 | } 70 | 71 | options := &extraction.ProcessOptions{ 72 | Timestamp: model.TimestampFromTime(time.Now()), 73 | } 74 | 75 | err = processor.ProcessSingle(resp.Body, ingestor, options) 76 | if err != nil { 77 | return fmt.Errorf("error getting processing samples for %s: %s", url, err) 78 | } 79 | return nil 80 | } 81 | 82 | type Ingester struct { 83 | acc plugins.Accumulator 84 | } 85 | 86 | // Ingest implements an extraction.Ingester. 87 | func (i *Ingester) Ingest(samples model.Samples) error { 88 | for _, sample := range samples { 89 | tags := map[string]string{} 90 | for key, value := range sample.Metric { 91 | if key == model.MetricNameLabel { 92 | continue 93 | } 94 | tags[string(key)] = string(value) 95 | } 96 | i.acc.Add(string(sample.Metric[model.MetricNameLabel]), float64(sample.Value), tags) 97 | } 98 | return nil 99 | } 100 | 101 | func init() { 102 | plugins.Add("prometheus", func() plugins.Plugin { 103 | return &Prometheus{} 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_test.go: -------------------------------------------------------------------------------- 1 | package disk 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | 8 | "github.com/influxdb/telegraf/plugins/system/ps/common" 9 | ) 10 | 11 | func TestDisk_usage(t *testing.T) { 12 | path := "/" 13 | if runtime.GOOS == "windows" { 14 | path = "C:" 15 | } 16 | v, err := DiskUsage(path) 17 | if err != nil { 18 | t.Errorf("error %v", err) 19 | } 20 | if v.Path != path { 21 | t.Errorf("error %v", err) 22 | } 23 | } 24 | 25 | func TestDisk_partitions(t *testing.T) { 26 | ret, err := DiskPartitions(false) 27 | if err != nil || len(ret) == 0 { 28 | t.Errorf("error %v", err) 29 | } 30 | empty := DiskPartitionStat{} 31 | for _, disk := range ret { 32 | if disk == empty { 33 | t.Errorf("Could not get device info %v", disk) 34 | } 35 | } 36 | } 37 | 38 | func TestDisk_io_counters(t *testing.T) { 39 | ret, err := DiskIOCounters() 40 | if err != nil { 41 | if err == common.NotImplementedError { 42 | t.SkipNow() 43 | } 44 | 45 | t.Errorf("error %v", err) 46 | } 47 | if len(ret) == 0 { 48 | t.Errorf("ret is empty", ret) 49 | } 50 | empty := DiskIOCountersStat{} 51 | for part, io := range ret { 52 | fmt.Println(io) 53 | if io == empty { 54 | t.Errorf("io_counter error %v, %v", part, io) 55 | } 56 | } 57 | } 58 | 59 | func TestDiskUsageStat_String(t *testing.T) { 60 | v := DiskUsageStat{ 61 | Path: "/", 62 | Total: 1000, 63 | Free: 2000, 64 | Used: 3000, 65 | UsedPercent: 50.1, 66 | InodesTotal: 4000, 67 | InodesUsed: 5000, 68 | InodesFree: 6000, 69 | InodesUsedPercent: 49.1, 70 | } 71 | e := `{"path":"/","total":1000,"free":2000,"used":3000,"used_percent":50.1,"inodes_total":4000,"inodes_used":5000,"inodes_free":6000,"inodes_used_percent":49.1}` 72 | if e != fmt.Sprintf("%v", v) { 73 | t.Errorf("DiskUsageStat string is invalid: %v", v) 74 | } 75 | } 76 | 77 | func TestDiskPartitionStat_String(t *testing.T) { 78 | v := DiskPartitionStat{ 79 | Device: "sd01", 80 | Mountpoint: "/", 81 | Fstype: "ext4", 82 | Opts: "ro", 83 | } 84 | e := `{"device":"sd01","mountpoint":"/","fstype":"ext4","opts":"ro"}` 85 | if e != fmt.Sprintf("%v", v) { 86 | t.Errorf("DiskUsageStat string is invalid: %v", v) 87 | } 88 | } 89 | 90 | func TestDiskIOCountersStat_String(t *testing.T) { 91 | v := DiskIOCountersStat{ 92 | Name: "sd01", 93 | ReadCount: 100, 94 | WriteCount: 200, 95 | ReadBytes: 300, 96 | WriteBytes: 400, 97 | SerialNumber: "SERIAL", 98 | } 99 | e := `{"read_count":100,"write_count":200,"read_bytes":300,"write_bytes":400,"read_time":0,"write_time":0,"name":"sd01","io_time":0,"serial_number":"SERIAL"}` 100 | if e != fmt.Sprintf("%v", v) { 101 | t.Errorf("DiskUsageStat string is invalid: %v", v) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /plugins/system/docker.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/influxdb/telegraf/plugins" 7 | ) 8 | 9 | type DockerStats struct { 10 | ps PS 11 | } 12 | 13 | func (_ *DockerStats) Description() string { 14 | return "Read metrics about docker containers" 15 | } 16 | 17 | func (_ *DockerStats) SampleConfig() string { return "" } 18 | 19 | func (s *DockerStats) Gather(acc plugins.Accumulator) error { 20 | containers, err := s.ps.DockerStat() 21 | if err != nil { 22 | return fmt.Errorf("error getting docker info: %s", err) 23 | } 24 | 25 | for _, cont := range containers { 26 | tags := map[string]string{ 27 | "id": cont.Id, 28 | "name": cont.Name, 29 | "command": cont.Command, 30 | } 31 | 32 | cts := cont.CPU 33 | 34 | acc.Add("user", cts.User, tags) 35 | acc.Add("system", cts.System, tags) 36 | acc.Add("idle", cts.Idle, tags) 37 | acc.Add("nice", cts.Nice, tags) 38 | acc.Add("iowait", cts.Iowait, tags) 39 | acc.Add("irq", cts.Irq, tags) 40 | acc.Add("softirq", cts.Softirq, tags) 41 | acc.Add("steal", cts.Steal, tags) 42 | acc.Add("guest", cts.Guest, tags) 43 | acc.Add("guestNice", cts.GuestNice, tags) 44 | acc.Add("stolen", cts.Stolen, tags) 45 | 46 | acc.Add("cache", cont.Mem.Cache, tags) 47 | acc.Add("rss", cont.Mem.RSS, tags) 48 | acc.Add("rss_huge", cont.Mem.RSSHuge, tags) 49 | acc.Add("mapped_file", cont.Mem.MappedFile, tags) 50 | acc.Add("swap_in", cont.Mem.Pgpgin, tags) 51 | acc.Add("swap_out", cont.Mem.Pgpgout, tags) 52 | acc.Add("page_fault", cont.Mem.Pgfault, tags) 53 | acc.Add("page_major_fault", cont.Mem.Pgmajfault, tags) 54 | acc.Add("inactive_anon", cont.Mem.InactiveAnon, tags) 55 | acc.Add("active_anon", cont.Mem.ActiveAnon, tags) 56 | acc.Add("inactive_file", cont.Mem.InactiveFile, tags) 57 | acc.Add("active_file", cont.Mem.ActiveFile, tags) 58 | acc.Add("unevictable", cont.Mem.Unevictable, tags) 59 | acc.Add("memory_limit", cont.Mem.HierarchicalMemoryLimit, tags) 60 | acc.Add("total_cache", cont.Mem.TotalCache, tags) 61 | acc.Add("total_rss", cont.Mem.TotalRSS, tags) 62 | acc.Add("total_rss_huge", cont.Mem.TotalRSSHuge, tags) 63 | acc.Add("total_mapped_file", cont.Mem.TotalMappedFile, tags) 64 | acc.Add("total_swap_in", cont.Mem.TotalPgpgIn, tags) 65 | acc.Add("total_swap_out", cont.Mem.TotalPgpgOut, tags) 66 | acc.Add("total_page_fault", cont.Mem.TotalPgFault, tags) 67 | acc.Add("total_page_major_fault", cont.Mem.TotalPgMajFault, tags) 68 | acc.Add("total_inactive_anon", cont.Mem.TotalInactiveAnon, tags) 69 | acc.Add("total_active_anon", cont.Mem.TotalActiveAnon, tags) 70 | acc.Add("total_inactive_file", cont.Mem.TotalInactiveFile, tags) 71 | acc.Add("total_active_file", cont.Mem.TotalActiveFile, tags) 72 | acc.Add("total_unevictable", cont.Mem.TotalUnevictable, tags) 73 | } 74 | 75 | return nil 76 | } 77 | 78 | func init() { 79 | plugins.Add("docker", func() plugins.Plugin { 80 | return &DockerStats{ps: &systemPS{}} 81 | }) 82 | } 83 | -------------------------------------------------------------------------------- /testutil/accumulator.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | type Point struct { 10 | Measurement string 11 | Value interface{} 12 | Tags map[string]string 13 | Values map[string]interface{} 14 | Time time.Time 15 | } 16 | 17 | type Accumulator struct { 18 | Points []*Point 19 | } 20 | 21 | func (a *Accumulator) Add(measurement string, value interface{}, tags map[string]string) { 22 | if tags == nil { 23 | tags = map[string]string{} 24 | } 25 | a.Points = append( 26 | a.Points, 27 | &Point{ 28 | Measurement: measurement, 29 | Value: value, 30 | Tags: tags, 31 | }, 32 | ) 33 | } 34 | 35 | func (a *Accumulator) AddValuesWithTime( 36 | measurement string, 37 | values map[string]interface{}, 38 | tags map[string]string, 39 | timestamp time.Time, 40 | ) { 41 | a.Points = append( 42 | a.Points, 43 | &Point{ 44 | Measurement: measurement, 45 | Values: values, 46 | Tags: tags, 47 | Time: timestamp, 48 | }, 49 | ) 50 | } 51 | 52 | func (a *Accumulator) Get(measurement string) (*Point, bool) { 53 | for _, p := range a.Points { 54 | if p.Measurement == measurement { 55 | return p, true 56 | } 57 | } 58 | 59 | return nil, false 60 | } 61 | 62 | func (a *Accumulator) CheckValue(measurement string, val interface{}) bool { 63 | for _, p := range a.Points { 64 | if p.Measurement == measurement { 65 | return p.Value == val 66 | } 67 | } 68 | 69 | return false 70 | } 71 | 72 | func (a *Accumulator) CheckTaggedValue(measurement string, val interface{}, tags map[string]string) bool { 73 | return a.ValidateTaggedValue(measurement, val, tags) == nil 74 | } 75 | 76 | func (a *Accumulator) ValidateTaggedValue(measurement string, val interface{}, tags map[string]string) error { 77 | if tags == nil { 78 | tags = map[string]string{} 79 | } 80 | for _, p := range a.Points { 81 | if !reflect.DeepEqual(tags, p.Tags) { 82 | continue 83 | } 84 | 85 | if p.Measurement == measurement { 86 | if p.Value != val { 87 | return fmt.Errorf("%v (%T) != %v (%T)", p.Value, p.Value, val, val) 88 | } 89 | return nil 90 | } 91 | } 92 | 93 | return fmt.Errorf("unknown measurement %s with tags %v", measurement, tags) 94 | } 95 | 96 | func (a *Accumulator) ValidateValue(measurement string, val interface{}) error { 97 | return a.ValidateTaggedValue(measurement, val, nil) 98 | } 99 | 100 | func (a *Accumulator) HasIntValue(measurement string) bool { 101 | for _, p := range a.Points { 102 | if p.Measurement == measurement { 103 | _, ok := p.Value.(int64) 104 | return ok 105 | } 106 | } 107 | 108 | return false 109 | } 110 | 111 | func (a *Accumulator) HasFloatValue(measurement string) bool { 112 | for _, p := range a.Points { 113 | if p.Measurement == measurement { 114 | _, ok := p.Value.(float64) 115 | return ok 116 | } 117 | } 118 | 119 | return false 120 | } 121 | -------------------------------------------------------------------------------- /plugins/mysql/mysql.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "database/sql" 5 | "strconv" 6 | "strings" 7 | 8 | _ "github.com/go-sql-driver/mysql" 9 | "github.com/influxdb/telegraf/plugins" 10 | ) 11 | 12 | type Mysql struct { 13 | Servers []string 14 | } 15 | 16 | var sampleConfig = ` 17 | # specify servers via a url matching: 18 | # [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]] 19 | # e.g. root:root@http://10.0.0.18/?tls=false 20 | # 21 | # If no servers are specified, then localhost is used as the host. 22 | servers = ["localhost"]` 23 | 24 | func (m *Mysql) SampleConfig() string { 25 | return sampleConfig 26 | } 27 | 28 | func (m *Mysql) Description() string { 29 | return "Read metrics from one or many mysql servers" 30 | } 31 | 32 | var localhost = "" 33 | 34 | func (m *Mysql) Gather(acc plugins.Accumulator) error { 35 | if len(m.Servers) == 0 { 36 | // if we can't get stats in this case, thats fine, don't report 37 | // an error. 38 | m.gatherServer(localhost, acc) 39 | return nil 40 | } 41 | 42 | for _, serv := range m.Servers { 43 | err := m.gatherServer(serv, acc) 44 | if err != nil { 45 | return err 46 | } 47 | } 48 | 49 | return nil 50 | } 51 | 52 | type mapping struct { 53 | onServer string 54 | inExport string 55 | } 56 | 57 | var mappings = []*mapping{ 58 | { 59 | onServer: "Bytes_", 60 | inExport: "bytes_", 61 | }, 62 | { 63 | onServer: "Com_", 64 | inExport: "commands_", 65 | }, 66 | { 67 | onServer: "Handler_", 68 | inExport: "handler_", 69 | }, 70 | { 71 | onServer: "Innodb_", 72 | inExport: "innodb_", 73 | }, 74 | { 75 | onServer: "Threads_", 76 | inExport: "threads_", 77 | }, 78 | } 79 | 80 | func (m *Mysql) gatherServer(serv string, acc plugins.Accumulator) error { 81 | if serv == "localhost" { 82 | serv = "" 83 | } 84 | 85 | db, err := sql.Open("mysql", serv) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | defer db.Close() 91 | 92 | rows, err := db.Query(`SHOW /*!50002 GLOBAL */ STATUS`) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | for rows.Next() { 98 | var name string 99 | var val interface{} 100 | 101 | err = rows.Scan(&name, &val) 102 | if err != nil { 103 | return err 104 | } 105 | 106 | var found bool 107 | 108 | for _, mapped := range mappings { 109 | if strings.HasPrefix(name, mapped.onServer) { 110 | i, _ := strconv.Atoi(string(val.([]byte))) 111 | acc.Add(mapped.inExport+name[len(mapped.onServer):], i, nil) 112 | found = true 113 | } 114 | } 115 | 116 | if found { 117 | continue 118 | } 119 | 120 | switch name { 121 | case "Queries": 122 | i, err := strconv.ParseInt(string(val.([]byte)), 10, 64) 123 | if err != nil { 124 | return err 125 | } 126 | 127 | acc.Add("queries", i, nil) 128 | case "Slow_queries": 129 | i, err := strconv.ParseInt(string(val.([]byte)), 10, 64) 130 | if err != nil { 131 | return err 132 | } 133 | 134 | acc.Add("slow_queries", i, nil) 135 | } 136 | } 137 | 138 | return nil 139 | } 140 | 141 | func init() { 142 | plugins.Add("mysql", func() plugins.Plugin { 143 | return &Mysql{} 144 | }) 145 | } 146 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package disk 4 | 5 | import ( 6 | "fmt" 7 | "os/exec" 8 | "strconv" 9 | "strings" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | ) 13 | 14 | const ( 15 | SectorSize = 512 16 | ) 17 | 18 | // Get disk partitions. 19 | // should use setmntent(3) but this implement use /etc/mtab file 20 | func DiskPartitions(all bool) ([]DiskPartitionStat, error) { 21 | 22 | filename := "/etc/mtab" 23 | lines, err := common.ReadLines(filename) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | ret := make([]DiskPartitionStat, 0, len(lines)) 29 | 30 | for _, line := range lines { 31 | fields := strings.Fields(line) 32 | d := DiskPartitionStat{ 33 | Device: fields[0], 34 | Mountpoint: fields[1], 35 | Fstype: fields[2], 36 | Opts: fields[3], 37 | } 38 | ret = append(ret, d) 39 | } 40 | 41 | return ret, nil 42 | } 43 | 44 | func DiskIOCounters() (map[string]DiskIOCountersStat, error) { 45 | filename := "/proc/diskstats" 46 | lines, err := common.ReadLines(filename) 47 | if err != nil { 48 | return nil, err 49 | } 50 | ret := make(map[string]DiskIOCountersStat, 0) 51 | empty := DiskIOCountersStat{} 52 | 53 | for _, line := range lines { 54 | fields := strings.Fields(line) 55 | name := fields[2] 56 | reads, err := strconv.ParseUint((fields[3]), 10, 64) 57 | if err != nil { 58 | return ret, err 59 | } 60 | rbytes, err := strconv.ParseUint((fields[5]), 10, 64) 61 | if err != nil { 62 | return ret, err 63 | } 64 | rtime, err := strconv.ParseUint((fields[6]), 10, 64) 65 | if err != nil { 66 | return ret, err 67 | } 68 | writes, err := strconv.ParseUint((fields[7]), 10, 64) 69 | if err != nil { 70 | return ret, err 71 | } 72 | wbytes, err := strconv.ParseUint((fields[9]), 10, 64) 73 | if err != nil { 74 | return ret, err 75 | } 76 | wtime, err := strconv.ParseUint((fields[10]), 10, 64) 77 | if err != nil { 78 | return ret, err 79 | } 80 | iotime, err := strconv.ParseUint((fields[12]), 10, 64) 81 | if err != nil { 82 | return ret, err 83 | } 84 | d := DiskIOCountersStat{ 85 | ReadBytes: rbytes * SectorSize, 86 | WriteBytes: wbytes * SectorSize, 87 | ReadCount: reads, 88 | WriteCount: writes, 89 | ReadTime: rtime, 90 | WriteTime: wtime, 91 | IoTime: iotime, 92 | } 93 | if d == empty { 94 | continue 95 | } 96 | d.Name = name 97 | 98 | d.SerialNumber = GetDiskSerialNumber(name) 99 | ret[name] = d 100 | } 101 | return ret, nil 102 | } 103 | 104 | func GetDiskSerialNumber(name string) string { 105 | n := fmt.Sprintf("--name=%s", name) 106 | out, err := exec.Command("/sbin/udevadm", "info", "--query=property", n).Output() 107 | 108 | // does not return error, just an empty string 109 | if err != nil { 110 | return "" 111 | } 112 | lines := strings.Split(string(out), "\n") 113 | for _, line := range lines { 114 | values := strings.Split(line, "=") 115 | if len(values) < 2 || values[0] != "ID_SERIAL" { 116 | // only get ID_SERIAL, not ID_SERIAL_SHORT 117 | continue 118 | } 119 | return values[1] 120 | } 121 | return "" 122 | } 123 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net_test.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestAddrString(t *testing.T) { 9 | v := Addr{IP: "192.168.0.1", Port: 8000} 10 | 11 | s := fmt.Sprintf("%v", v) 12 | if s != "{\"ip\":\"192.168.0.1\",\"port\":8000}" { 13 | t.Errorf("Addr string is invalid: %v", v) 14 | } 15 | } 16 | 17 | func TestNetIOCountersStatString(t *testing.T) { 18 | v := NetIOCountersStat{ 19 | Name: "test", 20 | BytesSent: 100, 21 | } 22 | e := `{"name":"test","bytes_sent":100,"bytes_recv":0,"packets_sent":0,"packets_recv":0,"errin":0,"errout":0,"dropin":0,"dropout":0}` 23 | if e != fmt.Sprintf("%v", v) { 24 | t.Errorf("NetIOCountersStat string is invalid: %v", v) 25 | } 26 | } 27 | 28 | func TestNetConnectionStatString(t *testing.T) { 29 | v := NetConnectionStat{ 30 | Fd: 10, 31 | Family: 10, 32 | Type: 10, 33 | } 34 | e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","pid":0}` 35 | if e != fmt.Sprintf("%v", v) { 36 | t.Errorf("NetConnectionStat string is invalid: %v", v) 37 | } 38 | 39 | } 40 | 41 | func TestNetIOCountersAll(t *testing.T) { 42 | v, err := NetIOCounters(false) 43 | per, err := NetIOCounters(true) 44 | if err != nil { 45 | t.Errorf("Could not get NetIOCounters: %v", err) 46 | } 47 | if len(v) != 1 { 48 | t.Errorf("Could not get NetIOCounters: %v", v) 49 | } 50 | if v[0].Name != "all" { 51 | t.Errorf("Invalid NetIOCounters: %v", v) 52 | } 53 | var pr uint64 54 | for _, p := range per { 55 | pr += p.PacketsRecv 56 | } 57 | if v[0].PacketsRecv != pr { 58 | t.Errorf("invalid sum value: %v, %v", v[0].PacketsRecv, pr) 59 | } 60 | } 61 | 62 | func TestNetIOCountersPerNic(t *testing.T) { 63 | v, err := NetIOCounters(true) 64 | if err != nil { 65 | t.Errorf("Could not get NetIOCounters: %v", err) 66 | } 67 | if len(v) == 0 { 68 | t.Errorf("Could not get NetIOCounters: %v", v) 69 | } 70 | for _, vv := range v { 71 | if vv.Name == "" { 72 | t.Errorf("Invalid NetIOCounters: %v", vv) 73 | } 74 | } 75 | } 76 | 77 | func Test_getNetIOCountersAll(t *testing.T) { 78 | n := []NetIOCountersStat{ 79 | NetIOCountersStat{ 80 | Name: "a", 81 | BytesRecv: 10, 82 | PacketsRecv: 10, 83 | }, 84 | NetIOCountersStat{ 85 | Name: "b", 86 | BytesRecv: 10, 87 | PacketsRecv: 10, 88 | Errin: 10, 89 | }, 90 | } 91 | ret, err := getNetIOCountersAll(n) 92 | if err != nil { 93 | t.Error(err) 94 | } 95 | if len(ret) != 1 { 96 | t.Errorf("invalid return count") 97 | } 98 | if ret[0].Name != "all" { 99 | t.Errorf("invalid return name") 100 | } 101 | if ret[0].BytesRecv != 20 { 102 | t.Errorf("invalid count bytesrecv") 103 | } 104 | if ret[0].Errin != 10 { 105 | t.Errorf("invalid count errin") 106 | } 107 | } 108 | 109 | func TestNetInterfaces(t *testing.T) { 110 | v, err := NetInterfaces() 111 | if err != nil { 112 | t.Errorf("Could not get NetInterfaceStat: %v", err) 113 | } 114 | if len(v) == 0 { 115 | t.Errorf("Could not get NetInterfaceStat: %v", err) 116 | } 117 | for _, vv := range v { 118 | if vv.Name == "" { 119 | t.Errorf("Invalid NetInterface: %v", vv) 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package host 4 | 5 | import ( 6 | "bytes" 7 | "encoding/binary" 8 | "io/ioutil" 9 | "os" 10 | "os/exec" 11 | "runtime" 12 | "strconv" 13 | "strings" 14 | "unsafe" 15 | 16 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 17 | ) 18 | 19 | func HostInfo() (*HostInfoStat, error) { 20 | ret := &HostInfoStat{ 21 | OS: runtime.GOOS, 22 | PlatformFamily: "darwin", 23 | } 24 | 25 | hostname, err := os.Hostname() 26 | if err != nil { 27 | return ret, err 28 | } 29 | ret.Hostname = hostname 30 | 31 | platform, family, version, err := GetPlatformInformation() 32 | if err == nil { 33 | ret.Platform = platform 34 | ret.PlatformFamily = family 35 | ret.PlatformVersion = version 36 | } 37 | system, role, err := GetVirtualization() 38 | if err == nil { 39 | ret.VirtualizationSystem = system 40 | ret.VirtualizationRole = role 41 | } 42 | 43 | values, err := common.DoSysctrl("kern.boottime") 44 | if err == nil { 45 | // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014 46 | v := strings.Replace(values[2], ",", "", 1) 47 | t, err := strconv.ParseUint(v, 10, 64) 48 | if err != nil { 49 | return ret, err 50 | } 51 | ret.Uptime = t 52 | } 53 | 54 | return ret, nil 55 | } 56 | 57 | func BootTime() (uint64, error) { 58 | values, err := common.DoSysctrl("kern.boottime") 59 | if err != nil { 60 | return 0, err 61 | } 62 | // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014 63 | v := strings.Replace(values[2], ",", "", 1) 64 | 65 | boottime, err := strconv.ParseInt(v, 10, 64) 66 | if err != nil { 67 | return 0, err 68 | } 69 | 70 | return uint64(boottime), nil 71 | } 72 | 73 | func Users() ([]UserStat, error) { 74 | utmpfile := "/var/run/utmpx" 75 | var ret []UserStat 76 | 77 | file, err := os.Open(utmpfile) 78 | if err != nil { 79 | return ret, err 80 | } 81 | 82 | buf, err := ioutil.ReadAll(file) 83 | if err != nil { 84 | return ret, err 85 | } 86 | 87 | u := Utmpx{} 88 | entrySize := int(unsafe.Sizeof(u)) 89 | count := len(buf) / entrySize 90 | 91 | for i := 0; i < count; i++ { 92 | b := buf[i*entrySize : i*entrySize+entrySize] 93 | 94 | var u Utmpx 95 | br := bytes.NewReader(b) 96 | err := binary.Read(br, binary.LittleEndian, &u) 97 | if err != nil { 98 | continue 99 | } 100 | if u.Type != 7 { // skip if not USERPROCESS 101 | continue 102 | } 103 | user := UserStat{ 104 | User: common.IntToString(u.User[:]), 105 | Terminal: common.IntToString(u.Line[:]), 106 | Host: common.IntToString(u.Host[:]), 107 | Started: int(u.Tv.Sec), 108 | } 109 | ret = append(ret, user) 110 | } 111 | 112 | return ret, nil 113 | 114 | } 115 | 116 | func GetPlatformInformation() (string, string, string, error) { 117 | platform := "" 118 | family := "" 119 | version := "" 120 | 121 | out, err := exec.Command("uname", "-s").Output() 122 | if err == nil { 123 | platform = strings.ToLower(strings.TrimSpace(string(out))) 124 | } 125 | 126 | out, err = exec.Command("uname", "-r").Output() 127 | if err == nil { 128 | version = strings.ToLower(strings.TrimSpace(string(out))) 129 | } 130 | 131 | return platform, family, version, nil 132 | } 133 | 134 | func GetVirtualization() (string, string, error) { 135 | system := "" 136 | role := "" 137 | 138 | return system, role, nil 139 | } 140 | -------------------------------------------------------------------------------- /plugins/system/ps/mem/mem_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package mem 4 | 5 | import ( 6 | "os/exec" 7 | "strconv" 8 | "strings" 9 | 10 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 11 | ) 12 | 13 | func VirtualMemory() (*VirtualMemoryStat, error) { 14 | pageSize, err := common.DoSysctrl("vm.stats.vm.v_page_size") 15 | if err != nil { 16 | return nil, err 17 | } 18 | p, err := strconv.ParseUint(pageSize[0], 10, 64) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | pageCount, err := common.DoSysctrl("vm.stats.vm.v_page_count") 24 | if err != nil { 25 | return nil, err 26 | } 27 | free, err := common.DoSysctrl("vm.stats.vm.v_free_count") 28 | if err != nil { 29 | return nil, err 30 | } 31 | active, err := common.DoSysctrl("vm.stats.vm.v_active_count") 32 | if err != nil { 33 | return nil, err 34 | } 35 | inactive, err := common.DoSysctrl("vm.stats.vm.v_inactive_count") 36 | if err != nil { 37 | return nil, err 38 | } 39 | cache, err := common.DoSysctrl("vm.stats.vm.v_cache_count") 40 | if err != nil { 41 | return nil, err 42 | } 43 | buffer, err := common.DoSysctrl("vfs.bufspace") 44 | if err != nil { 45 | return nil, err 46 | } 47 | wired, err := common.DoSysctrl("vm.stats.vm.v_wire_count") 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | parsed := make([]uint64, 0, 7) 53 | vv := []string{ 54 | pageCount[0], 55 | free[0], 56 | active[0], 57 | inactive[0], 58 | cache[0], 59 | buffer[0], 60 | wired[0], 61 | } 62 | for _, target := range vv { 63 | t, err := strconv.ParseUint(target, 10, 64) 64 | if err != nil { 65 | return nil, err 66 | } 67 | parsed = append(parsed, t) 68 | } 69 | 70 | ret := &VirtualMemoryStat{ 71 | Total: parsed[0] * p, 72 | Free: parsed[1] * p, 73 | Active: parsed[2] * p, 74 | Inactive: parsed[3] * p, 75 | Cached: parsed[4] * p, 76 | Buffers: parsed[5], 77 | Wired: parsed[6] * p, 78 | } 79 | 80 | // TODO: platform independent (worked freebsd?) 81 | ret.Available = ret.Free + ret.Buffers + ret.Cached 82 | 83 | ret.Used = ret.Total - ret.Free 84 | ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 85 | 86 | return ret, nil 87 | } 88 | 89 | // Return swapinfo 90 | // FreeBSD can have multiple swap devices. but use only first device 91 | func SwapMemory() (*SwapMemoryStat, error) { 92 | out, err := exec.Command("swapinfo").Output() 93 | if err != nil { 94 | return nil, err 95 | } 96 | var ret *SwapMemoryStat 97 | for _, line := range strings.Split(string(out), "\n") { 98 | values := strings.Fields(line) 99 | // skip title line 100 | if len(values) == 0 || values[0] == "Device" { 101 | continue 102 | } 103 | 104 | u := strings.Replace(values[4], "%", "", 1) 105 | total_v, err := strconv.ParseUint(values[1], 10, 64) 106 | if err != nil { 107 | return nil, err 108 | } 109 | used_v, err := strconv.ParseUint(values[2], 10, 64) 110 | if err != nil { 111 | return nil, err 112 | } 113 | free_v, err := strconv.ParseUint(values[3], 10, 64) 114 | if err != nil { 115 | return nil, err 116 | } 117 | up_v, err := strconv.ParseFloat(u, 64) 118 | if err != nil { 119 | return nil, err 120 | } 121 | 122 | ret = &SwapMemoryStat{ 123 | Total: total_v, 124 | Used: used_v, 125 | Free: free_v, 126 | UsedPercent: up_v, 127 | } 128 | } 129 | 130 | return ret, nil 131 | } 132 | -------------------------------------------------------------------------------- /plugins/memcached/memcached.go: -------------------------------------------------------------------------------- 1 | package memcached 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "net" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/influxdb/telegraf/plugins" 12 | ) 13 | 14 | // Memcached is a memcached plugin 15 | type Memcached struct { 16 | Servers []string 17 | } 18 | 19 | var sampleConfig = ` 20 | # An array of address to gather stats about. Specify an ip on hostname 21 | # with optional port. ie localhost, 10.0.0.1:11211, etc. 22 | # 23 | # If no servers are specified, then localhost is used as the host. 24 | servers = ["localhost"]` 25 | 26 | var defaultTimeout = 5 * time.Second 27 | 28 | // The list of metrics tha should be calculated 29 | var sendAsIs = []string{ 30 | "get_hits", 31 | "get_misses", 32 | "evictions", 33 | "limit_maxbytes", 34 | "bytes", 35 | } 36 | 37 | // SampleConfig returns sample configuration message 38 | func (m *Memcached) SampleConfig() string { 39 | return sampleConfig 40 | } 41 | 42 | // Description returns description of Memcached plugin 43 | func (m *Memcached) Description() string { 44 | return "Read metrics from one or many memcached servers" 45 | } 46 | 47 | // Gather reads stats from all configured servers accumulates stats 48 | func (m *Memcached) Gather(acc plugins.Accumulator) error { 49 | if len(m.Servers) == 0 { 50 | return m.gatherServer(":11211", acc) 51 | } 52 | 53 | for _, serverAddress := range m.Servers { 54 | if err := m.gatherServer(serverAddress, acc); err != nil { 55 | return err 56 | } 57 | } 58 | 59 | return nil 60 | } 61 | 62 | func (m *Memcached) gatherServer(address string, acc plugins.Accumulator) error { 63 | _, _, err := net.SplitHostPort(address) 64 | if err != nil { 65 | address = address + ":11211" 66 | } 67 | 68 | // Connect 69 | conn, err := net.DialTimeout("tcp", address, defaultTimeout) 70 | if err != nil { 71 | return err 72 | } 73 | defer conn.Close() 74 | 75 | // Extend connection 76 | conn.SetDeadline(time.Now().Add(defaultTimeout)) 77 | 78 | // Read and write buffer 79 | rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) 80 | 81 | // Send command 82 | if _, err = fmt.Fprint(rw, "stats\r\n"); err != nil { 83 | return err 84 | } 85 | if err = rw.Flush(); err != nil { 86 | return err 87 | } 88 | 89 | // Read response 90 | values := make(map[string]string) 91 | 92 | for { 93 | // Read line 94 | line, _, errRead := rw.Reader.ReadLine() 95 | if errRead != nil { 96 | return errRead 97 | } 98 | // Done 99 | if bytes.Equal(line, []byte("END")) { 100 | break 101 | } 102 | // Read values 103 | var name, value string 104 | n, errScan := fmt.Sscanf(string(line), "STAT %s %s\r\n", &name, &value) 105 | if errScan != nil || n != 2 { 106 | return fmt.Errorf("unexpected line in stats response: %q", line) 107 | } 108 | 109 | // Save values 110 | values[name] = value 111 | } 112 | 113 | // 114 | tags := map[string]string{"server": address} 115 | 116 | // Process values 117 | for _, key := range sendAsIs { 118 | if value, ok := values[key]; ok { 119 | // Mostly it is the number 120 | if iValue, errParse := strconv.ParseInt(value, 10, 64); errParse != nil { 121 | acc.Add(key, value, tags) 122 | } else { 123 | acc.Add(key, iValue, tags) 124 | } 125 | } 126 | } 127 | return nil 128 | } 129 | 130 | func init() { 131 | plugins.Add("memcached", func() plugins.Plugin { 132 | return &Memcached{} 133 | }) 134 | } 135 | -------------------------------------------------------------------------------- /plugins/system/ps/host/host_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package host 4 | 5 | import ( 6 | "bytes" 7 | "encoding/binary" 8 | "io/ioutil" 9 | "os" 10 | "os/exec" 11 | "runtime" 12 | "strconv" 13 | "strings" 14 | "unsafe" 15 | 16 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 17 | ) 18 | 19 | const ( 20 | UTNameSize = 16 /* see MAXLOGNAME in */ 21 | UTLineSize = 8 22 | UTHostSize = 16 23 | ) 24 | 25 | func HostInfo() (*HostInfoStat, error) { 26 | ret := &HostInfoStat{ 27 | OS: runtime.GOOS, 28 | PlatformFamily: "freebsd", 29 | } 30 | 31 | hostname, err := os.Hostname() 32 | if err != nil { 33 | return ret, err 34 | } 35 | ret.Hostname = hostname 36 | 37 | platform, family, version, err := GetPlatformInformation() 38 | if err == nil { 39 | ret.Platform = platform 40 | ret.PlatformFamily = family 41 | ret.PlatformVersion = version 42 | } 43 | system, role, err := GetVirtualization() 44 | if err == nil { 45 | ret.VirtualizationSystem = system 46 | ret.VirtualizationRole = role 47 | } 48 | 49 | values, err := common.DoSysctrl("kern.boottime") 50 | if err == nil { 51 | // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014 52 | v := strings.Replace(values[2], ",", "", 1) 53 | t, err := strconv.ParseUint(v, 10, 64) 54 | if err != nil { 55 | return ret, err 56 | } 57 | ret.Uptime = t 58 | } 59 | 60 | return ret, nil 61 | } 62 | 63 | func BootTime() (int64, error) { 64 | values, err := common.DoSysctrl("kern.boottime") 65 | if err != nil { 66 | return 0, err 67 | } 68 | // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014 69 | v := strings.Replace(values[2], ",", "", 1) 70 | 71 | boottime, err := strconv.ParseInt(v, 10, 64) 72 | if err != nil { 73 | return 0, err 74 | } 75 | 76 | return boottime, nil 77 | } 78 | 79 | func Users() ([]UserStat, error) { 80 | utmpfile := "/var/run/utmp" 81 | var ret []UserStat 82 | 83 | file, err := os.Open(utmpfile) 84 | if err != nil { 85 | return ret, err 86 | } 87 | 88 | buf, err := ioutil.ReadAll(file) 89 | if err != nil { 90 | return ret, err 91 | } 92 | 93 | u := Utmp{} 94 | entrySize := int(unsafe.Sizeof(u)) 95 | count := len(buf) / entrySize 96 | 97 | for i := 0; i < count; i++ { 98 | b := buf[i*entrySize : i*entrySize+entrySize] 99 | 100 | var u Utmp 101 | br := bytes.NewReader(b) 102 | err := binary.Read(br, binary.LittleEndian, &u) 103 | if err != nil || u.Time == 0 { 104 | continue 105 | } 106 | user := UserStat{ 107 | User: common.IntToString(u.Name[:]), 108 | Terminal: common.IntToString(u.Line[:]), 109 | Host: common.IntToString(u.Host[:]), 110 | Started: int(u.Time), 111 | } 112 | 113 | ret = append(ret, user) 114 | } 115 | 116 | return ret, nil 117 | 118 | } 119 | 120 | func GetPlatformInformation() (string, string, string, error) { 121 | platform := "" 122 | family := "" 123 | version := "" 124 | 125 | out, err := exec.Command("uname", "-s").Output() 126 | if err == nil { 127 | platform = strings.ToLower(strings.TrimSpace(string(out))) 128 | } 129 | 130 | out, err = exec.Command("uname", "-r").Output() 131 | if err == nil { 132 | version = strings.ToLower(strings.TrimSpace(string(out))) 133 | } 134 | 135 | return platform, family, version, nil 136 | } 137 | 138 | func GetVirtualization() (string, string, error) { 139 | system := "" 140 | role := "" 141 | 142 | return system, role, nil 143 | } 144 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "encoding/json" 5 | "runtime" 6 | "time" 7 | 8 | cpu "github.com/influxdb/telegraf/plugins/system/ps/cpu" 9 | ) 10 | 11 | type Process struct { 12 | Pid int32 `json:"pid"` 13 | name string 14 | status string 15 | numCtxSwitches *NumCtxSwitchesStat 16 | uids []int32 17 | gids []int32 18 | numThreads int32 19 | memInfo *MemoryInfoStat 20 | 21 | lastCPUTimes *cpu.CPUTimesStat 22 | lastCPUTime time.Time 23 | } 24 | 25 | type OpenFilesStat struct { 26 | Path string `json:"path"` 27 | Fd uint64 `json:"fd"` 28 | } 29 | 30 | type MemoryInfoStat struct { 31 | RSS uint64 `json:"rss"` // bytes 32 | VMS uint64 `json:"vms"` // bytes 33 | Swap uint64 `json:"swap"` // bytes 34 | } 35 | 36 | type RlimitStat struct { 37 | Resource int32 `json:"resource"` 38 | Soft int32 `json:"soft"` 39 | Hard int32 `json:"hard"` 40 | } 41 | 42 | type IOCountersStat struct { 43 | ReadCount uint64 `json:"read_count"` 44 | WriteCount uint64 `json:"write_count"` 45 | ReadBytes uint64 `json:"read_bytes"` 46 | WriteBytes uint64 `json:"write_bytes"` 47 | } 48 | 49 | type NumCtxSwitchesStat struct { 50 | Voluntary int64 `json:"voluntary"` 51 | Involuntary int64 `json:"involuntary"` 52 | } 53 | 54 | func (p Process) String() string { 55 | s, _ := json.Marshal(p) 56 | return string(s) 57 | } 58 | 59 | func (o OpenFilesStat) String() string { 60 | s, _ := json.Marshal(o) 61 | return string(s) 62 | } 63 | 64 | func (m MemoryInfoStat) String() string { 65 | s, _ := json.Marshal(m) 66 | return string(s) 67 | } 68 | 69 | func (r RlimitStat) String() string { 70 | s, _ := json.Marshal(r) 71 | return string(s) 72 | } 73 | 74 | func (i IOCountersStat) String() string { 75 | s, _ := json.Marshal(i) 76 | return string(s) 77 | } 78 | 79 | func (p NumCtxSwitchesStat) String() string { 80 | s, _ := json.Marshal(p) 81 | return string(s) 82 | } 83 | 84 | func PidExists(pid int32) (bool, error) { 85 | pids, err := Pids() 86 | if err != nil { 87 | return false, err 88 | } 89 | 90 | for _, i := range pids { 91 | if i == pid { 92 | return true, err 93 | } 94 | } 95 | 96 | return false, err 97 | } 98 | 99 | // If interval is 0, return difference from last call(non-blocking). 100 | // If interval > 0, wait interval sec and return diffrence between start and end. 101 | func (p *Process) CPUPercent(interval time.Duration) (float64, error) { 102 | numcpu := runtime.NumCPU() 103 | calculate := func(t1, t2 *cpu.CPUTimesStat, delta float64) float64 { 104 | if delta == 0 { 105 | return 0 106 | } 107 | delta_proc := (t2.User - t1.User) + (t2.System - t1.System) 108 | overall_percent := ((delta_proc / delta) * 100) * float64(numcpu) 109 | return overall_percent 110 | } 111 | 112 | cpuTimes, err := p.CPUTimes() 113 | if err != nil { 114 | return 0, err 115 | } 116 | 117 | if interval > 0 { 118 | p.lastCPUTimes = cpuTimes 119 | p.lastCPUTime = time.Now() 120 | time.Sleep(interval) 121 | cpuTimes, err = p.CPUTimes() 122 | if err != nil { 123 | return 0, err 124 | } 125 | } else { 126 | if p.lastCPUTimes == nil { 127 | // invoked first time 128 | p.lastCPUTimes, err = p.CPUTimes() 129 | if err != nil { 130 | return 0, err 131 | } 132 | p.lastCPUTime = time.Now() 133 | return 0, nil 134 | } 135 | } 136 | 137 | delta := (time.Now().Sub(p.lastCPUTime).Seconds()) * float64(numcpu) 138 | ret := calculate(p.lastCPUTimes, cpuTimes, float64(delta)) 139 | p.lastCPUTimes = cpuTimes 140 | p.lastCPUTime = time.Now() 141 | return ret, nil 142 | } 143 | -------------------------------------------------------------------------------- /plugins/system/ps/common/common.go: -------------------------------------------------------------------------------- 1 | // 2 | // gopsutil is a port of psutil(http://pythonhosted.org/psutil/). 3 | // This covers these architectures. 4 | // - linux (amd64, arm) 5 | // - freebsd (amd64) 6 | // - windows (amd64) 7 | package common 8 | 9 | import ( 10 | "bufio" 11 | "errors" 12 | "os" 13 | "reflect" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | var NotImplementedError = errors.New("not implemented yet") 19 | 20 | // ReadLines reads contents from file and splits them by new line. 21 | // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1). 22 | func ReadLines(filename string) ([]string, error) { 23 | return ReadLinesOffsetN(filename, 0, -1) 24 | } 25 | 26 | // ReadLines reads contents from file and splits them by new line. 27 | // The offset tells at which line number to start. 28 | // The count determines the number of lines to read (starting from offset): 29 | // n >= 0: at most n lines 30 | // n < 0: whole file 31 | func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) { 32 | f, err := os.Open(filename) 33 | if err != nil { 34 | return []string{""}, err 35 | } 36 | defer f.Close() 37 | 38 | var ret []string 39 | 40 | r := bufio.NewReader(f) 41 | for i := 0; i < n+int(offset) || n < 0; i++ { 42 | line, err := r.ReadString('\n') 43 | if err != nil { 44 | break 45 | } 46 | if i < int(offset) { 47 | continue 48 | } 49 | ret = append(ret, strings.Trim(line, "\n")) 50 | } 51 | 52 | return ret, nil 53 | } 54 | 55 | func IntToString(orig []int8) string { 56 | ret := make([]byte, len(orig)) 57 | size := -1 58 | for i, o := range orig { 59 | if o == 0 { 60 | size = i 61 | break 62 | } 63 | ret[i] = byte(o) 64 | } 65 | if size == -1 { 66 | size = len(orig) 67 | } 68 | 69 | return string(ret[0:size]) 70 | } 71 | 72 | func ByteToString(orig []byte) string { 73 | n := -1 74 | l := -1 75 | for i, b := range orig { 76 | // skip left side null 77 | if l == -1 && b == 0 { 78 | continue 79 | } 80 | if l == -1 { 81 | l = i 82 | } 83 | 84 | if b == 0 { 85 | break 86 | } 87 | n = i + 1 88 | } 89 | if n == -1 { 90 | return string(orig) 91 | } 92 | return string(orig[l:n]) 93 | } 94 | 95 | // Parse to int32 without error 96 | func mustParseInt32(val string) int32 { 97 | vv, _ := strconv.ParseInt(val, 10, 32) 98 | return int32(vv) 99 | } 100 | 101 | // Parse to uint64 without error 102 | func mustParseUint64(val string) uint64 { 103 | vv, _ := strconv.ParseInt(val, 10, 64) 104 | return uint64(vv) 105 | } 106 | 107 | // Parse to Float64 without error 108 | func mustParseFloat64(val string) float64 { 109 | vv, _ := strconv.ParseFloat(val, 64) 110 | return vv 111 | } 112 | 113 | // Check the target string slice containes src or not 114 | func StringContains(target []string, src string) bool { 115 | for _, t := range target { 116 | if strings.TrimSpace(t) == src { 117 | return true 118 | } 119 | } 120 | return false 121 | } 122 | 123 | // get struct attributes. 124 | // This method is used only for debugging platform dependent code. 125 | func attributes(m interface{}) map[string]reflect.Type { 126 | typ := reflect.TypeOf(m) 127 | if typ.Kind() == reflect.Ptr { 128 | typ = typ.Elem() 129 | } 130 | 131 | attrs := make(map[string]reflect.Type) 132 | if typ.Kind() != reflect.Struct { 133 | return nil 134 | } 135 | 136 | for i := 0; i < typ.NumField(); i++ { 137 | p := typ.Field(i) 138 | if !p.Anonymous { 139 | attrs[p.Name] = p.Type 140 | } 141 | } 142 | 143 | return attrs 144 | } 145 | 146 | func PathExists(filename string) bool { 147 | if _, err := os.Stat(filename); err == nil { 148 | return true 149 | } 150 | return false 151 | } 152 | -------------------------------------------------------------------------------- /plugins/system/ps.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | gonet "net" 5 | "strings" 6 | 7 | dc "github.com/fsouza/go-dockerclient" 8 | "github.com/influxdb/telegraf/plugins" 9 | "github.com/influxdb/telegraf/plugins/system/ps/common" 10 | "github.com/influxdb/telegraf/plugins/system/ps/cpu" 11 | "github.com/influxdb/telegraf/plugins/system/ps/disk" 12 | "github.com/influxdb/telegraf/plugins/system/ps/docker" 13 | "github.com/influxdb/telegraf/plugins/system/ps/load" 14 | "github.com/influxdb/telegraf/plugins/system/ps/mem" 15 | "github.com/influxdb/telegraf/plugins/system/ps/net" 16 | ) 17 | 18 | type DockerContainerStat struct { 19 | Id string 20 | Name string 21 | Command string 22 | CPU *cpu.CPUTimesStat 23 | Mem *docker.CgroupMemStat 24 | } 25 | 26 | type PS interface { 27 | LoadAvg() (*load.LoadAvgStat, error) 28 | CPUTimes() ([]cpu.CPUTimesStat, error) 29 | DiskUsage() ([]*disk.DiskUsageStat, error) 30 | NetIO() ([]net.NetIOCountersStat, error) 31 | DiskIO() (map[string]disk.DiskIOCountersStat, error) 32 | VMStat() (*mem.VirtualMemoryStat, error) 33 | SwapStat() (*mem.SwapMemoryStat, error) 34 | DockerStat() ([]*DockerContainerStat, error) 35 | } 36 | 37 | func add(acc plugins.Accumulator, 38 | name string, val float64, tags map[string]string) { 39 | if val >= 0 { 40 | acc.Add(name, val, tags) 41 | } 42 | } 43 | 44 | type systemPS struct { 45 | dockerClient *dc.Client 46 | } 47 | 48 | func (s *systemPS) LoadAvg() (*load.LoadAvgStat, error) { 49 | return load.LoadAvg() 50 | } 51 | 52 | func (s *systemPS) CPUTimes() ([]cpu.CPUTimesStat, error) { 53 | return cpu.CPUTimes(true) 54 | } 55 | 56 | func (s *systemPS) DiskUsage() ([]*disk.DiskUsageStat, error) { 57 | parts, err := disk.DiskPartitions(true) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | var usage []*disk.DiskUsageStat 63 | 64 | for _, p := range parts { 65 | du, err := disk.DiskUsage(p.Mountpoint) 66 | if err != nil { 67 | return nil, err 68 | } 69 | 70 | usage = append(usage, du) 71 | } 72 | 73 | return usage, nil 74 | } 75 | 76 | func (s *systemPS) NetIO() ([]net.NetIOCountersStat, error) { 77 | return net.NetIOCounters(true) 78 | } 79 | 80 | func (s *systemPS) DiskIO() (map[string]disk.DiskIOCountersStat, error) { 81 | m, err := disk.DiskIOCounters() 82 | if err == common.NotImplementedError { 83 | return nil, nil 84 | } 85 | 86 | return m, err 87 | } 88 | 89 | func (s *systemPS) VMStat() (*mem.VirtualMemoryStat, error) { 90 | return mem.VirtualMemory() 91 | } 92 | 93 | func (s *systemPS) SwapStat() (*mem.SwapMemoryStat, error) { 94 | return mem.SwapMemory() 95 | } 96 | 97 | func (s *systemPS) DockerStat() ([]*DockerContainerStat, error) { 98 | if s.dockerClient == nil { 99 | c, err := dc.NewClient("unix:///var/run/docker.sock") 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | s.dockerClient = c 105 | } 106 | 107 | opts := dc.ListContainersOptions{} 108 | 109 | list, err := s.dockerClient.ListContainers(opts) 110 | if err != nil { 111 | if _, ok := err.(*gonet.OpError); ok { 112 | return nil, nil 113 | } 114 | 115 | return nil, err 116 | } 117 | 118 | var stats []*DockerContainerStat 119 | 120 | for _, cont := range list { 121 | ctu, err := docker.CgroupCPUDocker(cont.ID) 122 | if err != nil { 123 | return nil, err 124 | } 125 | 126 | mem, err := docker.CgroupMemDocker(cont.ID) 127 | if err != nil { 128 | return nil, err 129 | } 130 | 131 | name := strings.Join(cont.Names, " ") 132 | 133 | stats = append(stats, &DockerContainerStat{ 134 | Id: cont.ID, 135 | Name: name, 136 | Command: cont.Command, 137 | CPU: ctu, 138 | Mem: mem, 139 | }) 140 | } 141 | 142 | return stats, nil 143 | } 144 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package cpu 4 | 5 | import ( 6 | "fmt" 7 | "regexp" 8 | "strconv" 9 | "strings" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | ) 13 | 14 | // sys/resource.h 15 | const ( 16 | CPUser = 0 17 | CPNice = 1 18 | CPSys = 2 19 | CPIntr = 3 20 | CPIdle = 4 21 | CPUStates = 5 22 | ) 23 | 24 | // time.h 25 | const ( 26 | ClocksPerSec = 128 27 | ) 28 | 29 | func CPUTimes(percpu bool) ([]CPUTimesStat, error) { 30 | var ret []CPUTimesStat 31 | 32 | var sysctlCall string 33 | var ncpu int 34 | if percpu { 35 | sysctlCall = "kern.cp_times" 36 | ncpu, _ = CPUCounts(true) 37 | } else { 38 | sysctlCall = "kern.cp_time" 39 | ncpu = 1 40 | } 41 | 42 | cpuTimes, err := common.DoSysctrl(sysctlCall) 43 | if err != nil { 44 | return ret, err 45 | } 46 | 47 | for i := 0; i < ncpu; i++ { 48 | offset := CPUStates * i 49 | user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 64) 50 | if err != nil { 51 | return ret, err 52 | } 53 | nice, err := strconv.ParseFloat(cpuTimes[CPNice+offset], 64) 54 | if err != nil { 55 | return ret, err 56 | } 57 | sys, err := strconv.ParseFloat(cpuTimes[CPSys+offset], 64) 58 | if err != nil { 59 | return ret, err 60 | } 61 | idle, err := strconv.ParseFloat(cpuTimes[CPIdle+offset], 64) 62 | if err != nil { 63 | return ret, err 64 | } 65 | intr, err := strconv.ParseFloat(cpuTimes[CPIntr+offset], 64) 66 | if err != nil { 67 | return ret, err 68 | } 69 | 70 | c := CPUTimesStat{ 71 | User: float64(user / ClocksPerSec), 72 | Nice: float64(nice / ClocksPerSec), 73 | System: float64(sys / ClocksPerSec), 74 | Idle: float64(idle / ClocksPerSec), 75 | Irq: float64(intr / ClocksPerSec), 76 | } 77 | if !percpu { 78 | c.CPU = "cpu-total" 79 | } else { 80 | c.CPU = fmt.Sprintf("cpu%d", i) 81 | } 82 | 83 | ret = append(ret, c) 84 | } 85 | 86 | return ret, nil 87 | } 88 | 89 | // Returns only one CPUInfoStat on FreeBSD 90 | func CPUInfo() ([]CPUInfoStat, error) { 91 | filename := "/var/run/dmesg.boot" 92 | lines, _ := common.ReadLines(filename) 93 | 94 | var ret []CPUInfoStat 95 | 96 | c := CPUInfoStat{} 97 | for _, line := range lines { 98 | if matches := regexp.MustCompile(`CPU:\s+(.+) \(([\d.]+).+\)`).FindStringSubmatch(line); matches != nil { 99 | c.ModelName = matches[1] 100 | t, err := strconv.ParseFloat(matches[2], 64) 101 | if err != nil { 102 | return ret, nil 103 | } 104 | c.Mhz = t 105 | } else if matches := regexp.MustCompile(`Origin = "(.+)" Id = (.+) Family = (.+) Model = (.+) Stepping = (.+)`).FindStringSubmatch(line); matches != nil { 106 | c.VendorID = matches[1] 107 | c.Family = matches[3] 108 | c.Model = matches[4] 109 | t, err := strconv.ParseInt(matches[5], 10, 32) 110 | if err != nil { 111 | return ret, nil 112 | } 113 | c.Stepping = int32(t) 114 | } else if matches := regexp.MustCompile(`Features=.+<(.+)>`).FindStringSubmatch(line); matches != nil { 115 | for _, v := range strings.Split(matches[1], ",") { 116 | c.Flags = append(c.Flags, strings.ToLower(v)) 117 | } 118 | } else if matches := regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`).FindStringSubmatch(line); matches != nil { 119 | for _, v := range strings.Split(matches[1], ",") { 120 | c.Flags = append(c.Flags, strings.ToLower(v)) 121 | } 122 | } else if matches := regexp.MustCompile(`Logical CPUs per core: (\d+)`).FindStringSubmatch(line); matches != nil { 123 | // FIXME: no this line? 124 | t, err := strconv.ParseInt(matches[1], 10, 32) 125 | if err != nil { 126 | return ret, nil 127 | } 128 | c.Cores = int32(t) 129 | } 130 | 131 | } 132 | 133 | return append(ret, c), nil 134 | } 135 | -------------------------------------------------------------------------------- /plugins/system/ps/process/types_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Hand Writing 6 | // - all pointer in ExternProc to uint64 7 | 8 | // +build ignore 9 | 10 | /* 11 | Input to cgo -godefs. 12 | */ 13 | 14 | // +godefs map struct_in_addr [4]byte /* in_addr */ 15 | // +godefs map struct_in6_addr [16]byte /* in6_addr */ 16 | // +godefs map struct_ [16]byte /* in6_addr */ 17 | 18 | package process 19 | 20 | /* 21 | #define __DARWIN_UNIX03 0 22 | #define KERNEL 23 | #define _DARWIN_USE_64_BIT_INODE 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | enum { 63 | sizeofPtr = sizeof(void*), 64 | }; 65 | 66 | union sockaddr_all { 67 | struct sockaddr s1; // this one gets used for fields 68 | struct sockaddr_in s2; // these pad it out 69 | struct sockaddr_in6 s3; 70 | struct sockaddr_un s4; 71 | struct sockaddr_dl s5; 72 | }; 73 | 74 | struct sockaddr_any { 75 | struct sockaddr addr; 76 | char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; 77 | }; 78 | 79 | struct ucred_queue { 80 | struct ucred *tqe_next; 81 | struct ucred **tqe_prev; 82 | TRACEBUF 83 | }; 84 | 85 | */ 86 | import "C" 87 | 88 | // Machine characteristics; for internal use. 89 | 90 | const ( 91 | sizeofPtr = C.sizeofPtr 92 | sizeofShort = C.sizeof_short 93 | sizeofInt = C.sizeof_int 94 | sizeofLong = C.sizeof_long 95 | sizeofLongLong = C.sizeof_longlong 96 | ) 97 | 98 | // Basic types 99 | 100 | type ( 101 | _C_short C.short 102 | _C_int C.int 103 | _C_long C.long 104 | _C_long_long C.longlong 105 | ) 106 | 107 | // Time 108 | 109 | type Timespec C.struct_timespec 110 | 111 | type Timeval C.struct_timeval 112 | 113 | // Processes 114 | 115 | type Rusage C.struct_rusage 116 | 117 | type Rlimit C.struct_rlimit 118 | 119 | type UGid_t C.gid_t 120 | 121 | type KinfoProc C.struct_kinfo_proc 122 | 123 | type Eproc C.struct_eproc 124 | 125 | type Proc C.struct_proc 126 | 127 | type Session C.struct_session 128 | 129 | type ucred C.struct_ucred 130 | 131 | type Uucred C.struct__ucred 132 | 133 | type Upcred C.struct__pcred 134 | 135 | type Vmspace C.struct_vmspace 136 | 137 | type Sigacts C.struct_sigacts 138 | 139 | type ExternProc C.struct_extern_proc 140 | 141 | type Itimerval C.struct_itimerval 142 | 143 | type Vnode C.struct_vnode 144 | 145 | type Pgrp C.struct_pgrp 146 | 147 | type UserStruct C.struct_user 148 | 149 | type Au_session C.struct_au_session 150 | 151 | type Posix_cred C.struct_posix_cred 152 | 153 | type Label C.struct_label 154 | 155 | type AuditinfoAddr C.struct_auditinfo_addr 156 | type AuMask C.struct_au_mask 157 | type AuTidAddr C.struct_au_tid_addr 158 | 159 | // TAILQ(ucred) 160 | type UcredQueue C.struct_ucred_queue 161 | -------------------------------------------------------------------------------- /plugins/rethinkdb/rethinkdb_data.go: -------------------------------------------------------------------------------- 1 | package rethinkdb 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | 7 | "github.com/influxdb/telegraf/plugins" 8 | ) 9 | 10 | type serverStatus struct { 11 | Id string `gorethink:"id"` 12 | Network struct { 13 | Addresses []Address `gorethink:"canonical_addresses"` 14 | Hostname string `gorethink:"hostname"` 15 | DriverPort int `gorethink:"reql_port"` 16 | } `gorethink:"network"` 17 | Process struct { 18 | Version string `gorethink:"version"` 19 | RunningSince time.Time `gorethink:"time_started"` 20 | } `gorethink:"process"` 21 | } 22 | 23 | type Address struct { 24 | Host string `gorethink:"host"` 25 | Port int `gorethink:"port"` 26 | } 27 | 28 | type stats struct { 29 | Engine Engine `gorethink:"query_engine"` 30 | } 31 | 32 | type Engine struct { 33 | ClientConns int64 `gorethink:"client_connections,omitempty"` 34 | ClientActive int64 `gorethink:"clients_active,omitempty"` 35 | QueriesPerSec int64 `gorethink:"queries_per_sec,omitempty"` 36 | TotalQueries int64 `gorethink:"queries_total,omitempty"` 37 | ReadsPerSec int64 `gorethink:"read_docs_per_sec,omitempty"` 38 | TotalReads int64 `gorethink:"read_docs_total,omitempty"` 39 | WritesPerSec int64 `gorethink:"written_docs_per_sec,omitempty"` 40 | TotalWrites int64 `gorethink:"written_docs_total,omitempty"` 41 | } 42 | 43 | type tableStatus struct { 44 | Id string `gorethink:"id"` 45 | DB string `gorethink:"db"` 46 | Name string `gorethink:"name"` 47 | } 48 | 49 | type tableStats struct { 50 | Engine Engine `gorethink:"query_engine"` 51 | Storage Storage `gorethink:"storage_engine"` 52 | } 53 | 54 | type Storage struct { 55 | Cache Cache `gorethink:"cache"` 56 | Disk Disk `gorethink:"disk"` 57 | } 58 | 59 | type Cache struct { 60 | BytesInUse int64 `gorethink:"in_use_bytes"` 61 | } 62 | 63 | type Disk struct { 64 | ReadBytesPerSec int64 `gorethink:"read_bytes_per_sec"` 65 | ReadBytesTotal int64 `gorethink:"read_bytes_total"` 66 | WriteBytesPerSec int64 `gorethik:"written_bytes_per_sec"` 67 | WriteBytesTotal int64 `gorethink:"written_bytes_total"` 68 | SpaceUsage SpaceUsage `gorethink:"space_usage"` 69 | } 70 | 71 | type SpaceUsage struct { 72 | Data int64 `gorethink:"data_bytes"` 73 | Garbage int64 `gorethink:"garbage_bytes"` 74 | Metadata int64 `gorethink:"metadata_bytes"` 75 | Prealloc int64 `gorethink:"preallocated_bytes"` 76 | } 77 | 78 | var engineStats = map[string]string{ 79 | "active_clients": "ClientActive", 80 | "clients": "ClientConns", 81 | "queries_per_sec": "QueriesPerSec", 82 | "total_queries": "TotalQueries", 83 | "read_docs_per_sec": "ReadsPerSec", 84 | "total_reads": "TotalReads", 85 | "written_docs_per_sec": "WritesPerSec", 86 | "total_writes": "TotalWrites", 87 | } 88 | 89 | func (e *Engine) AddEngineStats(keys []string, acc plugins.Accumulator, tags map[string]string) { 90 | engine := reflect.ValueOf(e).Elem() 91 | for _, key := range keys { 92 | acc.Add( 93 | key, 94 | engine.FieldByName(engineStats[key]).Interface(), 95 | tags, 96 | ) 97 | } 98 | } 99 | 100 | func (s *Storage) AddStats(acc plugins.Accumulator, tags map[string]string) { 101 | acc.Add("cache_bytes_in_use", s.Cache.BytesInUse, tags) 102 | acc.Add("disk_read_bytes_per_sec", s.Disk.ReadBytesPerSec, tags) 103 | acc.Add("disk_read_bytes_total", s.Disk.ReadBytesTotal, tags) 104 | acc.Add("disk_written_bytes_per_sec", s.Disk.WriteBytesPerSec, tags) 105 | acc.Add("disk_written_bytes_total", s.Disk.WriteBytesTotal, tags) 106 | acc.Add("disk_usage_data_bytes", s.Disk.SpaceUsage.Data, tags) 107 | acc.Add("disk_usage_garbage_bytes", s.Disk.SpaceUsage.Garbage, tags) 108 | acc.Add("disk_usage_metadata_bytes", s.Disk.SpaceUsage.Metadata, tags) 109 | acc.Add("disk_usage_preallocated_bytes", s.Disk.SpaceUsage.Prealloc, tags) 110 | } 111 | -------------------------------------------------------------------------------- /plugins/kafka_consumer/kafka_consumer.go: -------------------------------------------------------------------------------- 1 | package kafka_consumer 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "time" 7 | 8 | "github.com/influxdb/influxdb/tsdb" 9 | "github.com/influxdb/telegraf/plugins" 10 | "github.com/wvanbergen/kafka/consumergroup" 11 | "gopkg.in/Shopify/sarama.v1" 12 | ) 13 | 14 | type Kafka struct { 15 | ConsumerGroupName string 16 | Topic string 17 | ZookeeperPeers []string 18 | Consumer *consumergroup.ConsumerGroup 19 | BatchSize int 20 | } 21 | 22 | var sampleConfig = ` 23 | # topic to consume 24 | topic = "topic_with_metrics" 25 | 26 | # the name of the consumer group 27 | consumerGroupName = "telegraf_metrics_consumers" 28 | 29 | # an array of Zookeeper connection strings 30 | zookeeperPeers = ["localhost:2181"] 31 | 32 | # Batch size of points sent to InfluxDB 33 | batchSize = 1000` 34 | 35 | func (k *Kafka) SampleConfig() string { 36 | return sampleConfig 37 | } 38 | 39 | func (k *Kafka) Description() string { 40 | return "read metrics from a Kafka topic" 41 | } 42 | 43 | type Metric struct { 44 | Measurement string `json:"measurement"` 45 | Values map[string]interface{} `json:"values"` 46 | Tags map[string]string `json:"tags"` 47 | Time time.Time `json:"time"` 48 | } 49 | 50 | func (k *Kafka) Gather(acc plugins.Accumulator) error { 51 | var consumerErr error 52 | metricQueue := make(chan []byte, 200) 53 | 54 | if k.Consumer == nil { 55 | k.Consumer, consumerErr = consumergroup.JoinConsumerGroup( 56 | k.ConsumerGroupName, 57 | []string{k.Topic}, 58 | k.ZookeeperPeers, 59 | nil, 60 | ) 61 | 62 | if consumerErr != nil { 63 | return consumerErr 64 | } 65 | 66 | c := make(chan os.Signal, 1) 67 | halt := make(chan bool, 1) 68 | signal.Notify(c, os.Interrupt) 69 | go func() { 70 | <-c 71 | halt <- true 72 | emitMetrics(k, acc, metricQueue) 73 | k.Consumer.Close() 74 | }() 75 | 76 | go readFromKafka(k.Consumer.Messages(), metricQueue, k.BatchSize, k.Consumer.CommitUpto, halt) 77 | } 78 | 79 | return emitMetrics(k, acc, metricQueue) 80 | } 81 | 82 | func emitMetrics(k *Kafka, acc plugins.Accumulator, metricConsumer <-chan []byte) error { 83 | timeout := time.After(1 * time.Second) 84 | 85 | for { 86 | select { 87 | case batch := <-metricConsumer: 88 | var points []tsdb.Point 89 | var err error 90 | if points, err = tsdb.ParsePoints(batch); err != nil { 91 | return err 92 | } 93 | 94 | for _, point := range points { 95 | acc.AddValuesWithTime(point.Name(), point.Fields(), point.Tags(), point.Time()) 96 | } 97 | case <-timeout: 98 | return nil 99 | } 100 | } 101 | } 102 | 103 | const millisecond = 1000000 * time.Nanosecond 104 | 105 | type ack func(*sarama.ConsumerMessage) error 106 | 107 | func readFromKafka(kafkaMsgs <-chan *sarama.ConsumerMessage, metricProducer chan<- []byte, maxBatchSize int, ackMsg ack, halt <-chan bool) { 108 | batch := make([]byte, 0) 109 | currentBatchSize := 0 110 | timeout := time.After(500 * millisecond) 111 | var msg *sarama.ConsumerMessage 112 | 113 | for { 114 | select { 115 | case msg = <-kafkaMsgs: 116 | if currentBatchSize != 0 { 117 | batch = append(batch, '\n') 118 | } 119 | 120 | batch = append(batch, msg.Value...) 121 | currentBatchSize++ 122 | 123 | if currentBatchSize == maxBatchSize { 124 | metricProducer <- batch 125 | currentBatchSize = 0 126 | batch = make([]byte, 0) 127 | ackMsg(msg) 128 | } 129 | case <-timeout: 130 | if currentBatchSize != 0 { 131 | metricProducer <- batch 132 | currentBatchSize = 0 133 | batch = make([]byte, 0) 134 | ackMsg(msg) 135 | } 136 | 137 | timeout = time.After(500 * millisecond) 138 | case <-halt: 139 | if currentBatchSize != 0 { 140 | metricProducer <- batch 141 | ackMsg(msg) 142 | } 143 | 144 | return 145 | } 146 | } 147 | } 148 | 149 | func init() { 150 | plugins.Add("kafka", func() plugins.Plugin { 151 | return &Kafka{} 152 | }) 153 | } 154 | -------------------------------------------------------------------------------- /plugins/system/ps/common/common_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package common 4 | 5 | import ( 6 | "fmt" 7 | "os/exec" 8 | "strings" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | // for double values 14 | type PDH_FMT_COUNTERVALUE_DOUBLE struct { 15 | CStatus uint32 16 | DoubleValue float64 17 | } 18 | 19 | // for 64 bit integer values 20 | type PDH_FMT_COUNTERVALUE_LARGE struct { 21 | CStatus uint32 22 | LargeValue int64 23 | } 24 | 25 | // for long values 26 | type PDH_FMT_COUNTERVALUE_LONG struct { 27 | CStatus uint32 28 | LongValue int32 29 | padding [4]byte 30 | } 31 | 32 | // windows system const 33 | const ( 34 | ERROR_SUCCESS = 0 35 | ERROR_FILE_NOT_FOUND = 2 36 | DRIVE_REMOVABLE = 2 37 | DRIVE_FIXED = 3 38 | HKEY_LOCAL_MACHINE = 0x80000002 39 | RRF_RT_REG_SZ = 0x00000002 40 | RRF_RT_REG_DWORD = 0x00000010 41 | PDH_FMT_LONG = 0x00000100 42 | PDH_FMT_DOUBLE = 0x00000200 43 | PDH_FMT_LARGE = 0x00000400 44 | PDH_INVALID_DATA = 0xc0000bc6 45 | PDH_INVALID_HANDLE = 0xC0000bbc 46 | PDH_NO_DATA = 0x800007d5 47 | ) 48 | 49 | var ( 50 | Modkernel32 = syscall.NewLazyDLL("kernel32.dll") 51 | ModNt = syscall.NewLazyDLL("ntdll.dll") 52 | ModPdh = syscall.NewLazyDLL("pdh.dll") 53 | 54 | ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") 55 | ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") 56 | PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery") 57 | PdhAddCounter = ModPdh.NewProc("PdhAddCounterW") 58 | PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData") 59 | PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue") 60 | PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery") 61 | ) 62 | 63 | type FILETIME struct { 64 | DwLowDateTime uint32 65 | DwHighDateTime uint32 66 | } 67 | 68 | // borrowed from net/interface_windows.go 69 | func BytePtrToString(p *uint8) string { 70 | a := (*[10000]uint8)(unsafe.Pointer(p)) 71 | i := 0 72 | for a[i] != 0 { 73 | i++ 74 | } 75 | return string(a[:i]) 76 | } 77 | 78 | // exec wmic and return lines splited by newline 79 | func GetWmic(target string, query ...string) ([][]string, error) { 80 | cmd := []string{target} 81 | cmd = append(cmd, query...) 82 | cmd = append(cmd, "/format:csv") 83 | out, err := exec.Command("wmic", cmd...).Output() 84 | if err != nil { 85 | return [][]string{}, err 86 | } 87 | lines := strings.Split(string(out), "\r\r\n") 88 | if len(lines) <= 2 { 89 | return [][]string{}, fmt.Errorf("wmic result malformed: [%q]", lines) 90 | } 91 | var ret [][]string 92 | for _, l := range lines[2:] { // skip first two lines 93 | var lr []string 94 | for _, r := range strings.Split(l, ",") { 95 | if r == "" { 96 | continue 97 | } 98 | lr = append(lr, strings.TrimSpace(r)) 99 | } 100 | if len(lr) != 0 { 101 | ret = append(ret, lr) 102 | } 103 | } 104 | 105 | return ret, nil 106 | 107 | } 108 | 109 | // CounterInfo 110 | // copied from https://github.com/mackerelio/mackerel-agent/ 111 | type CounterInfo struct { 112 | PostName string 113 | CounterName string 114 | Counter syscall.Handle 115 | } 116 | 117 | // CreateQuery XXX 118 | // copied from https://github.com/mackerelio/mackerel-agent/ 119 | func CreateQuery() (syscall.Handle, error) { 120 | var query syscall.Handle 121 | r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query))) 122 | if r != 0 { 123 | return 0, err 124 | } 125 | return query, nil 126 | } 127 | 128 | // CreateCounter XXX 129 | func CreateCounter(query syscall.Handle, pname, cname string) (*CounterInfo, error) { 130 | var counter syscall.Handle 131 | r, _, err := PdhAddCounter.Call( 132 | uintptr(query), 133 | uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(cname))), 134 | 0, 135 | uintptr(unsafe.Pointer(&counter))) 136 | if r != 0 { 137 | return nil, err 138 | } 139 | return &CounterInfo{ 140 | PostName: pname, 141 | CounterName: cname, 142 | Counter: counter, 143 | }, nil 144 | } 145 | -------------------------------------------------------------------------------- /plugins/system/ps/net/net.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "encoding/json" 5 | "net" 6 | ) 7 | 8 | type NetIOCountersStat struct { 9 | Name string `json:"name"` // interface name 10 | BytesSent uint64 `json:"bytes_sent"` // number of bytes sent 11 | BytesRecv uint64 `json:"bytes_recv"` // number of bytes received 12 | PacketsSent uint64 `json:"packets_sent"` // number of packets sent 13 | PacketsRecv uint64 `json:"packets_recv"` // number of packets received 14 | Errin uint64 `json:"errin"` // total number of errors while receiving 15 | Errout uint64 `json:"errout"` // total number of errors while sending 16 | Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped 17 | Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD) 18 | } 19 | 20 | // Addr is implemented compatibility to psutil 21 | type Addr struct { 22 | IP string `json:"ip"` 23 | Port uint32 `json:"port"` 24 | } 25 | 26 | type NetConnectionStat struct { 27 | Fd uint32 `json:"fd"` 28 | Family uint32 `json:"family"` 29 | Type uint32 `json:"type"` 30 | Laddr Addr `json:"localaddr"` 31 | Raddr Addr `json:"remoteaddr"` 32 | Status string `json:"status"` 33 | Pid int32 `json:"pid"` 34 | } 35 | 36 | // NetInterfaceAddr is designed for represent interface addresses 37 | type NetInterfaceAddr struct { 38 | Addr string `json:"addr"` 39 | } 40 | 41 | type NetInterfaceStat struct { 42 | MTU int `json:"mtu"` // maximum transmission unit 43 | Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100" 44 | HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form 45 | Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast 46 | Addrs []NetInterfaceAddr `json:"addrs"` 47 | } 48 | 49 | func (n NetIOCountersStat) String() string { 50 | s, _ := json.Marshal(n) 51 | return string(s) 52 | } 53 | 54 | func (n NetConnectionStat) String() string { 55 | s, _ := json.Marshal(n) 56 | return string(s) 57 | } 58 | 59 | func (a Addr) String() string { 60 | s, _ := json.Marshal(a) 61 | return string(s) 62 | } 63 | 64 | func (n NetInterfaceStat) String() string { 65 | s, _ := json.Marshal(n) 66 | return string(s) 67 | } 68 | 69 | func (n NetInterfaceAddr) String() string { 70 | s, _ := json.Marshal(n) 71 | return string(s) 72 | } 73 | 74 | func NetInterfaces() ([]NetInterfaceStat, error) { 75 | is, err := net.Interfaces() 76 | if err != nil { 77 | return nil, err 78 | } 79 | ret := make([]NetInterfaceStat, 0, len(is)) 80 | for _, ifi := range is { 81 | 82 | var flags []string 83 | if ifi.Flags&net.FlagUp != 0 { 84 | flags = append(flags, "up") 85 | } 86 | if ifi.Flags&net.FlagBroadcast != 0 { 87 | flags = append(flags, "broadcast") 88 | } 89 | if ifi.Flags&net.FlagLoopback != 0 { 90 | flags = append(flags, "loopback") 91 | } 92 | if ifi.Flags&net.FlagPointToPoint != 0 { 93 | flags = append(flags, "pointtopoint") 94 | } 95 | if ifi.Flags&net.FlagMulticast != 0 { 96 | flags = append(flags, "multicast") 97 | } 98 | 99 | r := NetInterfaceStat{ 100 | Name: ifi.Name, 101 | MTU: ifi.MTU, 102 | HardwareAddr: ifi.HardwareAddr.String(), 103 | Flags: flags, 104 | } 105 | addrs, err := ifi.Addrs() 106 | if err == nil { 107 | r.Addrs = make([]NetInterfaceAddr, 0, len(addrs)) 108 | for _, addr := range addrs { 109 | r.Addrs = append(r.Addrs, NetInterfaceAddr{ 110 | Addr: addr.String(), 111 | }) 112 | } 113 | 114 | } 115 | ret = append(ret, r) 116 | } 117 | 118 | return ret, nil 119 | } 120 | 121 | func getNetIOCountersAll(n []NetIOCountersStat) ([]NetIOCountersStat, error) { 122 | r := NetIOCountersStat{ 123 | Name: "all", 124 | } 125 | for _, nic := range n { 126 | r.BytesRecv += nic.BytesRecv 127 | r.PacketsRecv += nic.PacketsRecv 128 | r.Errin += nic.Errin 129 | r.Dropin += nic.Dropin 130 | r.BytesSent += nic.BytesSent 131 | r.PacketsSent += nic.PacketsSent 132 | r.Errout += nic.Errout 133 | r.Dropout += nic.Dropout 134 | } 135 | 136 | return []NetIOCountersStat{r}, nil 137 | } 138 | -------------------------------------------------------------------------------- /etc/config.sample.toml: -------------------------------------------------------------------------------- 1 | # Telegraf configuration 2 | 3 | # If this file is missing an [agent] section, you must first generate a 4 | # valid config with 'telegraf -sample-config > telegraf.toml' 5 | 6 | # Telegraf is entirely plugin driven. All metrics are gathered from the 7 | # declared plugins. 8 | 9 | # Even if a plugin has no configuration, it must be declared in here 10 | # to be active. Declaring a plugin means just specifying the name 11 | # as a section with no variables. To deactivate a plugin, comment 12 | # out the name and any variables. 13 | 14 | # Use 'telegraf -config telegraf.toml -test' to see what metrics a config 15 | # file would generate. 16 | 17 | # One rule that plugins conform to is wherever a connection string 18 | # can be passed, the values '' and 'localhost' are treated specially. 19 | # They indicate to the plugin to use their own builtin configuration to 20 | # connect to the local system. 21 | 22 | # NOTE: The configuration has a few required parameters. They are marked 23 | # with 'required'. Be sure to edit those to make this configuration work. 24 | 25 | # Configuration for influxdb server to send metrics to 26 | [influxdb] 27 | # The full HTTP endpoint URL for your InfluxDB instance 28 | url = "http://localhost:8086" # required. 29 | 30 | # The target database for metrics. This database must already exist 31 | database = "telegraf" # required. 32 | 33 | # username = "telegraf" 34 | # password = "metricsmetricsmetricsmetrics" 35 | 36 | # Set the user agent for the POSTs (can be useful for log differentiation) 37 | # user_agent = "telegraf" 38 | # tags = { "dc": "us-east-1" } 39 | 40 | # Tags can also be specified via a normal map, but only one form at a time: 41 | 42 | # [influxdb.tags] 43 | # dc = "us-east-1" 44 | 45 | # Configuration for telegraf itself 46 | # [agent] 47 | # interval = "10s" 48 | # debug = false 49 | # hostname = "prod3241" 50 | 51 | # PLUGINS 52 | 53 | # Read metrics about cpu usage 54 | [cpu] 55 | # no configuration 56 | 57 | # Read metrics about disk usage by mount point 58 | [disk] 59 | # no configuration 60 | 61 | # Read metrics about docker containers 62 | [docker] 63 | # no configuration 64 | 65 | # Read metrics about disk IO by device 66 | [io] 67 | # no configuration 68 | 69 | # Read metrics about memory usage 70 | [mem] 71 | # no configuration 72 | 73 | # Read metrics from one or many mysql servers 74 | [mysql] 75 | 76 | # specify servers via a url matching: 77 | # [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]] 78 | # e.g. root:root@http://10.0.0.18/?tls=false 79 | # 80 | # If no servers are specified, then localhost is used as the host. 81 | servers = ["localhost"] 82 | 83 | # Read metrics about network interface usage 84 | [net] 85 | 86 | # By default, telegraf gathers stats from any up interface (excluding loopback) 87 | # Setting interfaces will tell it to gather these explicit interfaces, 88 | # regardless of status. 89 | # 90 | # interfaces = ["eth0", ... ] 91 | 92 | # Read metrics from one or many postgresql servers 93 | [postgresql] 94 | 95 | # specify servers via an array of tables 96 | [[postgresql.servers]] 97 | 98 | # specify address via a url matching: 99 | # postgres://[pqgotest[:password]]@localhost?sslmode=[disable|verify-ca|verify-full] 100 | # or a simple string: 101 | # host=localhost user=pqotest password=... sslmode=... 102 | # 103 | # All connection parameters are optional. By default, the host is localhost 104 | # and the user is the currently running user. For localhost, we default 105 | # to sslmode=disable as well. 106 | # 107 | 108 | address = "sslmode=disable" 109 | 110 | # A list of databases to pull metrics about. If not specified, metrics for all 111 | # databases are gathered. 112 | 113 | # databases = ["app_production", "blah_testing"] 114 | 115 | # [[postgresql.servers]] 116 | # address = "influx@remoteserver" 117 | 118 | # Read metrics from one or many redis servers 119 | [redis] 120 | 121 | # An array of address to gather stats about. Specify an ip on hostname 122 | # with optional port. ie localhost, 10.10.3.33:18832, etc. 123 | # 124 | # If no servers are specified, then localhost is used as the host. 125 | servers = ["localhost"] 126 | 127 | # Read metrics about swap memory usage 128 | [swap] 129 | # no configuration 130 | 131 | # Read metrics about system load 132 | [system] 133 | # no configuration 134 | 135 | -------------------------------------------------------------------------------- /plugins/postgresql/postgresql.go: -------------------------------------------------------------------------------- 1 | package postgresql 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/influxdb/telegraf/plugins" 7 | 8 | _ "github.com/lib/pq" 9 | ) 10 | 11 | type Server struct { 12 | Address string 13 | Databases []string 14 | } 15 | 16 | type Postgresql struct { 17 | Servers []*Server 18 | } 19 | 20 | var sampleConfig = ` 21 | # specify servers via an array of tables 22 | [[postgresql.servers]] 23 | 24 | # specify address via a url matching: 25 | # postgres://[pqgotest[:password]]@localhost?sslmode=[disable|verify-ca|verify-full] 26 | # or a simple string: 27 | # host=localhost user=pqotest password=... sslmode=... 28 | # 29 | # All connection parameters are optional. By default, the host is localhost 30 | # and the user is the currently running user. For localhost, we default 31 | # to sslmode=disable as well. 32 | # 33 | 34 | address = "sslmode=disable" 35 | 36 | # A list of databases to pull metrics about. If not specified, metrics for all 37 | # databases are gathered. 38 | 39 | # databases = ["app_production", "blah_testing"] 40 | 41 | # [[postgresql.servers]] 42 | # address = "influx@remoteserver" 43 | ` 44 | 45 | func (p *Postgresql) SampleConfig() string { 46 | return sampleConfig 47 | } 48 | 49 | func (p *Postgresql) Description() string { 50 | return "Read metrics from one or many postgresql servers" 51 | } 52 | 53 | var localhost = &Server{Address: "sslmode=disable"} 54 | 55 | func (p *Postgresql) Gather(acc plugins.Accumulator) error { 56 | if len(p.Servers) == 0 { 57 | p.gatherServer(localhost, acc) 58 | return nil 59 | } 60 | 61 | for _, serv := range p.Servers { 62 | err := p.gatherServer(serv, acc) 63 | if err != nil { 64 | return err 65 | } 66 | } 67 | 68 | return nil 69 | } 70 | 71 | func (p *Postgresql) gatherServer(serv *Server, acc plugins.Accumulator) error { 72 | if serv.Address == "" || serv.Address == "localhost" { 73 | serv = localhost 74 | } 75 | 76 | db, err := sql.Open("postgres", serv.Address) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | defer db.Close() 82 | 83 | if len(serv.Databases) == 0 { 84 | rows, err := db.Query(`SELECT * FROM pg_stat_database`) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | defer rows.Close() 90 | 91 | for rows.Next() { 92 | err := p.accRow(rows, acc, serv.Address) 93 | if err != nil { 94 | return err 95 | } 96 | } 97 | 98 | return rows.Err() 99 | } else { 100 | for _, name := range serv.Databases { 101 | row := db.QueryRow(`SELECT * FROM pg_stat_database WHERE datname=$1`, name) 102 | 103 | err := p.accRow(row, acc, serv.Address) 104 | if err != nil { 105 | return err 106 | } 107 | } 108 | } 109 | 110 | return nil 111 | } 112 | 113 | type scanner interface { 114 | Scan(dest ...interface{}) error 115 | } 116 | 117 | func (p *Postgresql) accRow(row scanner, acc plugins.Accumulator, server string) error { 118 | var ignore interface{} 119 | var name string 120 | var commit, rollback, read, hit int64 121 | var returned, fetched, inserted, updated, deleted int64 122 | var conflicts, temp_files, temp_bytes, deadlocks int64 123 | var read_time, write_time float64 124 | 125 | err := row.Scan(&ignore, &name, &ignore, 126 | &commit, &rollback, 127 | &read, &hit, 128 | &returned, &fetched, &inserted, &updated, &deleted, 129 | &conflicts, &temp_files, &temp_bytes, 130 | &deadlocks, &read_time, &write_time, 131 | &ignore, 132 | ) 133 | 134 | if err != nil { 135 | return err 136 | } 137 | 138 | tags := map[string]string{"server": server, "db": name} 139 | 140 | acc.Add("xact_commit", commit, tags) 141 | acc.Add("xact_rollback", rollback, tags) 142 | acc.Add("blks_read", read, tags) 143 | acc.Add("blks_hit", hit, tags) 144 | acc.Add("tup_returned", returned, tags) 145 | acc.Add("tup_fetched", fetched, tags) 146 | acc.Add("tup_inserted", inserted, tags) 147 | acc.Add("tup_updated", updated, tags) 148 | acc.Add("tup_deleted", deleted, tags) 149 | acc.Add("conflicts", conflicts, tags) 150 | acc.Add("temp_files", temp_files, tags) 151 | acc.Add("temp_bytes", temp_bytes, tags) 152 | acc.Add("deadlocks", deadlocks, tags) 153 | acc.Add("blk_read_time", read_time, tags) 154 | acc.Add("blk_write_time", read_time, tags) 155 | 156 | return nil 157 | } 158 | 159 | func init() { 160 | plugins.Add("postgresql", func() plugins.Plugin { 161 | return &Postgresql{} 162 | }) 163 | } 164 | -------------------------------------------------------------------------------- /plugins/system/ps/disk/disk_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd 2 | 3 | package disk 4 | 5 | import ( 6 | "bytes" 7 | "encoding/binary" 8 | "strconv" 9 | "syscall" 10 | "unsafe" 11 | 12 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 13 | ) 14 | 15 | const ( 16 | CTLKern = 1 17 | KernDevstat = 773 18 | KernDevstatAll = 772 19 | ) 20 | 21 | func DiskPartitions(all bool) ([]DiskPartitionStat, error) { 22 | var ret []DiskPartitionStat 23 | 24 | // get length 25 | count, err := syscall.Getfsstat(nil, MNT_WAIT) 26 | if err != nil { 27 | return ret, err 28 | } 29 | 30 | fs := make([]Statfs, count) 31 | _, err = Getfsstat(fs, MNT_WAIT) 32 | 33 | for _, stat := range fs { 34 | opts := "rw" 35 | if stat.Flags&MNT_RDONLY != 0 { 36 | opts = "ro" 37 | } 38 | if stat.Flags&MNT_SYNCHRONOUS != 0 { 39 | opts += ",sync" 40 | } 41 | if stat.Flags&MNT_NOEXEC != 0 { 42 | opts += ",noexec" 43 | } 44 | if stat.Flags&MNT_NOSUID != 0 { 45 | opts += ",nosuid" 46 | } 47 | if stat.Flags&MNT_UNION != 0 { 48 | opts += ",union" 49 | } 50 | if stat.Flags&MNT_ASYNC != 0 { 51 | opts += ",async" 52 | } 53 | if stat.Flags&MNT_SUIDDIR != 0 { 54 | opts += ",suiddir" 55 | } 56 | if stat.Flags&MNT_SOFTDEP != 0 { 57 | opts += ",softdep" 58 | } 59 | if stat.Flags&MNT_NOSYMFOLLOW != 0 { 60 | opts += ",nosymfollow" 61 | } 62 | if stat.Flags&MNT_GJOURNAL != 0 { 63 | opts += ",gjounalc" 64 | } 65 | if stat.Flags&MNT_MULTILABEL != 0 { 66 | opts += ",multilabel" 67 | } 68 | if stat.Flags&MNT_ACLS != 0 { 69 | opts += ",acls" 70 | } 71 | if stat.Flags&MNT_NOATIME != 0 { 72 | opts += ",noattime" 73 | } 74 | if stat.Flags&MNT_NOCLUSTERR != 0 { 75 | opts += ",nocluster" 76 | } 77 | if stat.Flags&MNT_NOCLUSTERW != 0 { 78 | opts += ",noclusterw" 79 | } 80 | if stat.Flags&MNT_NFS4ACLS != 0 { 81 | opts += ",nfs4acls" 82 | } 83 | 84 | d := DiskPartitionStat{ 85 | Device: common.IntToString(stat.Mntfromname[:]), 86 | Mountpoint: common.IntToString(stat.Mntonname[:]), 87 | Fstype: common.IntToString(stat.Fstypename[:]), 88 | Opts: opts, 89 | } 90 | ret = append(ret, d) 91 | } 92 | 93 | return ret, nil 94 | } 95 | 96 | func DiskIOCounters() (map[string]DiskIOCountersStat, error) { 97 | // statinfo->devinfo->devstat 98 | // /usr/include/devinfo.h 99 | 100 | // sysctl.sysctl ('kern.devstat.all', 0) 101 | ret := make(map[string]DiskIOCountersStat) 102 | mib := []int32{CTLKern, KernDevstat, KernDevstatAll} 103 | 104 | buf, length, err := common.CallSyscall(mib) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | ds := Devstat{} 110 | devstatLen := int(unsafe.Sizeof(ds)) 111 | count := int(length / uint64(devstatLen)) 112 | 113 | buf = buf[8:] // devstat.all has version in the head. 114 | // parse buf to Devstat 115 | for i := 0; i < count; i++ { 116 | b := buf[i*devstatLen : i*devstatLen+devstatLen] 117 | d, err := parseDevstat(b) 118 | if err != nil { 119 | continue 120 | } 121 | un := strconv.Itoa(int(d.Unit_number)) 122 | name := common.IntToString(d.Device_name[:]) + un 123 | 124 | ds := DiskIOCountersStat{ 125 | ReadCount: d.Operations[DEVSTAT_READ], 126 | WriteCount: d.Operations[DEVSTAT_WRITE], 127 | ReadBytes: d.Bytes[DEVSTAT_READ], 128 | WriteBytes: d.Bytes[DEVSTAT_WRITE], 129 | ReadTime: d.Duration[DEVSTAT_READ].Compute(), 130 | WriteTime: d.Duration[DEVSTAT_WRITE].Compute(), 131 | Name: name, 132 | } 133 | ret[name] = ds 134 | } 135 | 136 | return ret, nil 137 | } 138 | 139 | func (b Bintime) Compute() uint64 { 140 | BINTIME_SCALE := 5.42101086242752217003726400434970855712890625e-20 141 | return uint64(b.Sec) + b.Frac*uint64(BINTIME_SCALE) 142 | } 143 | 144 | // BT2LD(time) ((long double)(time).sec + (time).frac * BINTIME_SCALE) 145 | 146 | // Getfsstat is borrowed from pkg/syscall/syscall_freebsd.go 147 | // change Statfs_t to Statfs in order to get more information 148 | func Getfsstat(buf []Statfs, flags int) (n int, err error) { 149 | var _p0 unsafe.Pointer 150 | var bufsize uintptr 151 | if len(buf) > 0 { 152 | _p0 = unsafe.Pointer(&buf[0]) 153 | bufsize = unsafe.Sizeof(Statfs{}) * uintptr(len(buf)) 154 | } 155 | r0, _, e1 := syscall.Syscall(syscall.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) 156 | n = int(r0) 157 | if e1 != 0 { 158 | err = e1 159 | } 160 | return 161 | } 162 | 163 | func parseDevstat(buf []byte) (Devstat, error) { 164 | var ds Devstat 165 | br := bytes.NewReader(buf) 166 | // err := binary.Read(br, binary.LittleEndian, &ds) 167 | err := Read(br, binary.LittleEndian, &ds) 168 | if err != nil { 169 | return ds, err 170 | } 171 | 172 | return ds, nil 173 | } 174 | -------------------------------------------------------------------------------- /plugins/system/ps/process/process_darwin_amd64.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs types_darwin.go 3 | 4 | package process 5 | 6 | const ( 7 | sizeofPtr = 0x8 8 | sizeofShort = 0x2 9 | sizeofInt = 0x4 10 | sizeofLong = 0x8 11 | sizeofLongLong = 0x8 12 | ) 13 | 14 | type ( 15 | _C_short int16 16 | _C_int int32 17 | _C_long int64 18 | _C_long_long int64 19 | ) 20 | 21 | type Timespec struct { 22 | Sec int64 23 | Nsec int64 24 | } 25 | 26 | type Timeval struct { 27 | Sec int64 28 | Usec int32 29 | Pad_cgo_0 [4]byte 30 | } 31 | 32 | type Rusage struct { 33 | Utime Timeval 34 | Stime Timeval 35 | Maxrss int64 36 | Ixrss int64 37 | Idrss int64 38 | Isrss int64 39 | Minflt int64 40 | Majflt int64 41 | Nswap int64 42 | Inblock int64 43 | Oublock int64 44 | Msgsnd int64 45 | Msgrcv int64 46 | Nsignals int64 47 | Nvcsw int64 48 | Nivcsw int64 49 | } 50 | 51 | type Rlimit struct { 52 | Cur uint64 53 | Max uint64 54 | } 55 | 56 | type UGid_t uint32 57 | 58 | type KinfoProc struct { 59 | Proc ExternProc 60 | Eproc Eproc 61 | } 62 | 63 | type Eproc struct { 64 | Paddr *uint64 65 | Sess *Session 66 | Pcred Upcred 67 | Ucred Uucred 68 | Pad_cgo_0 [4]byte 69 | Vm Vmspace 70 | Ppid int32 71 | Pgid int32 72 | Jobc int16 73 | Pad_cgo_1 [2]byte 74 | Tdev int32 75 | Tpgid int32 76 | Pad_cgo_2 [4]byte 77 | Tsess *Session 78 | Wmesg [8]int8 79 | Xsize int32 80 | Xrssize int16 81 | Xccount int16 82 | Xswrss int16 83 | Pad_cgo_3 [2]byte 84 | Flag int32 85 | Login [12]int8 86 | Spare [4]int32 87 | Pad_cgo_4 [4]byte 88 | } 89 | 90 | type Proc struct{} 91 | 92 | type Session struct{} 93 | 94 | type ucred struct { 95 | Link _Ctype_struct___0 96 | Ref uint64 97 | Posix Posix_cred 98 | Label *Label 99 | Audit Au_session 100 | } 101 | 102 | type Uucred struct { 103 | Ref int32 104 | Uid uint32 105 | Ngroups int16 106 | Pad_cgo_0 [2]byte 107 | Groups [16]uint32 108 | } 109 | 110 | type Upcred struct { 111 | Pc_lock [72]int8 112 | Pc_ucred *ucred 113 | P_ruid uint32 114 | P_svuid uint32 115 | P_rgid uint32 116 | P_svgid uint32 117 | P_refcnt int32 118 | Pad_cgo_0 [4]byte 119 | } 120 | 121 | type Vmspace struct { 122 | Dummy int32 123 | Pad_cgo_0 [4]byte 124 | Dummy2 *int8 125 | Dummy3 [5]int32 126 | Pad_cgo_1 [4]byte 127 | Dummy4 [3]*int8 128 | } 129 | 130 | type Sigacts struct{} 131 | 132 | type ExternProc struct { 133 | P_un [16]byte 134 | P_vmspace uint64 135 | P_sigacts uint64 136 | Pad_cgo_0 [3]byte 137 | P_flag int32 138 | P_stat int8 139 | P_pid int32 140 | P_oppid int32 141 | P_dupfd int32 142 | Pad_cgo_1 [4]byte 143 | User_stack uint64 144 | Exit_thread uint64 145 | P_debugger int32 146 | Sigwait int32 147 | P_estcpu uint32 148 | P_cpticks int32 149 | P_pctcpu uint32 150 | Pad_cgo_2 [4]byte 151 | P_wchan uint64 152 | P_wmesg uint64 153 | P_swtime uint32 154 | P_slptime uint32 155 | P_realtimer Itimerval 156 | P_rtime Timeval 157 | P_uticks uint64 158 | P_sticks uint64 159 | P_iticks uint64 160 | P_traceflag int32 161 | Pad_cgo_3 [4]byte 162 | P_tracep uint64 163 | P_siglist int32 164 | Pad_cgo_4 [4]byte 165 | P_textvp uint64 166 | P_holdcnt int32 167 | P_sigmask uint32 168 | P_sigignore uint32 169 | P_sigcatch uint32 170 | P_priority uint8 171 | P_usrpri uint8 172 | P_nice int8 173 | P_comm [17]int8 174 | Pad_cgo_5 [4]byte 175 | P_pgrp uint64 176 | P_addr uint64 177 | P_xstat uint16 178 | P_acflag uint16 179 | Pad_cgo_6 [4]byte 180 | P_ru uint64 181 | } 182 | 183 | type Itimerval struct { 184 | Interval Timeval 185 | Value Timeval 186 | } 187 | 188 | type Vnode struct{} 189 | 190 | type Pgrp struct{} 191 | 192 | type UserStruct struct{} 193 | 194 | type Au_session struct { 195 | Aia_p *AuditinfoAddr 196 | Mask AuMask 197 | } 198 | 199 | type Posix_cred struct { 200 | Uid uint32 201 | Ruid uint32 202 | Svuid uint32 203 | Ngroups int16 204 | Pad_cgo_0 [2]byte 205 | Groups [16]uint32 206 | Rgid uint32 207 | Svgid uint32 208 | Gmuid uint32 209 | Flags int32 210 | } 211 | 212 | type Label struct{} 213 | 214 | type AuditinfoAddr struct { 215 | Auid uint32 216 | Mask AuMask 217 | Termid AuTidAddr 218 | Asid int32 219 | Flags uint64 220 | } 221 | type AuMask struct { 222 | Success uint32 223 | Failure uint32 224 | } 225 | type AuTidAddr struct { 226 | Port int32 227 | Type uint32 228 | Addr [4]uint32 229 | } 230 | 231 | type UcredQueue struct { 232 | Next *ucred 233 | Prev **ucred 234 | } 235 | -------------------------------------------------------------------------------- /plugins/system/ps/docker/docker_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package docker 4 | 5 | import ( 6 | "encoding/json" 7 | "os/exec" 8 | "path" 9 | "strconv" 10 | "strings" 11 | 12 | "github.com/influxdb/telegraf/plugins/system/ps/common" 13 | "github.com/influxdb/telegraf/plugins/system/ps/cpu" 14 | ) 15 | 16 | // GetDockerIDList returnes a list of DockerID. 17 | // This requires certain permission. 18 | func GetDockerIDList() ([]string, error) { 19 | path, err := exec.LookPath("docker") 20 | if err != nil { 21 | return nil, ErrNotAvailable 22 | } 23 | 24 | out, err := exec.Command(path, "ps", "-q", "--no-trunc").Output() 25 | if err != nil { 26 | return []string{}, err 27 | } 28 | 29 | lines := strings.Split(string(out), "\n") 30 | ret := make([]string, 0, len(lines)) 31 | 32 | for _, l := range lines { 33 | if l == "" { 34 | continue 35 | } 36 | 37 | ret = append(ret, l) 38 | } 39 | 40 | return ret, nil 41 | } 42 | 43 | // CgroupCPU returnes specified cgroup id CPU status. 44 | // containerid is same as docker id if you use docker. 45 | // If you use container via systemd.slice, you could use 46 | // containerid = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ 47 | func CgroupCPU(containerid string, base string) (*cpu.CPUTimesStat, error) { 48 | if len(base) == 0 { 49 | base = "/sys/fs/cgroup/cpuacct/docker" 50 | } 51 | path := path.Join(base, containerid, "cpuacct.stat") 52 | 53 | lines, err := common.ReadLines(path) 54 | if err != nil { 55 | return nil, err 56 | } 57 | // empty containerid means all cgroup 58 | if len(containerid) == 0 { 59 | containerid = "all" 60 | } 61 | ret := &cpu.CPUTimesStat{CPU: containerid} 62 | for _, line := range lines { 63 | fields := strings.Split(line, " ") 64 | if fields[0] == "user" { 65 | user, err := strconv.ParseFloat(fields[1], 64) 66 | if err == nil { 67 | ret.User = float64(user) 68 | } 69 | } 70 | if fields[0] == "system" { 71 | system, err := strconv.ParseFloat(fields[1], 64) 72 | if err == nil { 73 | ret.System = float64(system) 74 | } 75 | } 76 | } 77 | 78 | return ret, nil 79 | } 80 | 81 | func CgroupCPUDocker(containerid string) (*cpu.CPUTimesStat, error) { 82 | return CgroupCPU(containerid, "/sys/fs/cgroup/cpuacct/docker") 83 | } 84 | 85 | func CgroupMem(containerid string, base string) (*CgroupMemStat, error) { 86 | if len(base) == 0 { 87 | base = "/sys/fs/cgroup/memory/docker" 88 | } 89 | path := path.Join(base, containerid, "memory.stat") 90 | // empty containerid means all cgroup 91 | if len(containerid) == 0 { 92 | containerid = "all" 93 | } 94 | lines, err := common.ReadLines(path) 95 | if err != nil { 96 | return nil, err 97 | } 98 | ret := &CgroupMemStat{ContainerID: containerid} 99 | for _, line := range lines { 100 | fields := strings.Split(line, " ") 101 | v, err := strconv.ParseUint(fields[1], 10, 64) 102 | if err != nil { 103 | continue 104 | } 105 | switch fields[0] { 106 | case "cache": 107 | ret.Cache = v 108 | case "rss": 109 | ret.RSS = v 110 | case "rss_huge": 111 | ret.RSSHuge = v 112 | case "mapped_file": 113 | ret.MappedFile = v 114 | case "pgpgin": 115 | ret.Pgpgin = v 116 | case "pgpgout": 117 | ret.Pgpgout = v 118 | case "pgfault": 119 | ret.Pgfault = v 120 | case "pgmajfault": 121 | ret.Pgmajfault = v 122 | case "inactive_anon": 123 | ret.InactiveAnon = v 124 | case "active_anon": 125 | ret.ActiveAnon = v 126 | case "inactive_file": 127 | ret.InactiveFile = v 128 | case "active_file": 129 | ret.ActiveFile = v 130 | case "unevictable": 131 | ret.Unevictable = v 132 | case "hierarchical_memory_limit": 133 | ret.HierarchicalMemoryLimit = v 134 | case "total_cache": 135 | ret.TotalCache = v 136 | case "total_rss": 137 | ret.TotalRSS = v 138 | case "total_rss_huge": 139 | ret.TotalRSSHuge = v 140 | case "total_mapped_file": 141 | ret.TotalMappedFile = v 142 | case "total_pgpgin": 143 | ret.TotalPgpgIn = v 144 | case "total_pgpgout": 145 | ret.TotalPgpgOut = v 146 | case "total_pgfault": 147 | ret.TotalPgFault = v 148 | case "total_pgmajfault": 149 | ret.TotalPgMajFault = v 150 | case "total_inactive_anon": 151 | ret.TotalInactiveAnon = v 152 | case "total_active_anon": 153 | ret.TotalActiveAnon = v 154 | case "total_inactive_file": 155 | ret.TotalInactiveFile = v 156 | case "total_active_file": 157 | ret.TotalActiveFile = v 158 | case "total_unevictable": 159 | ret.TotalUnevictable = v 160 | } 161 | } 162 | return ret, nil 163 | } 164 | 165 | func CgroupMemDocker(containerid string) (*CgroupMemStat, error) { 166 | return CgroupMem(containerid, "/sys/fs/cgroup/memory/docker") 167 | } 168 | 169 | func (m CgroupMemStat) String() string { 170 | s, _ := json.Marshal(m) 171 | return string(s) 172 | } 173 | -------------------------------------------------------------------------------- /plugins/system/ps/cpu/cpu_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package cpu 4 | 5 | import ( 6 | "errors" 7 | "os/exec" 8 | "strconv" 9 | "strings" 10 | 11 | common "github.com/influxdb/telegraf/plugins/system/ps/common" 12 | ) 13 | 14 | func CPUTimes(percpu bool) ([]CPUTimesStat, error) { 15 | filename := "/proc/stat" 16 | var lines = []string{} 17 | if percpu { 18 | var startIdx uint = 1 19 | for { 20 | linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1) 21 | line := linen[0] 22 | if !strings.HasPrefix(line, "cpu") { 23 | break 24 | } 25 | lines = append(lines, line) 26 | startIdx += 1 27 | } 28 | } else { 29 | lines, _ = common.ReadLinesOffsetN(filename, 0, 1) 30 | } 31 | 32 | ret := make([]CPUTimesStat, 0, len(lines)) 33 | 34 | for _, line := range lines { 35 | ct, err := parseStatLine(line) 36 | if err != nil { 37 | continue 38 | } 39 | ret = append(ret, *ct) 40 | 41 | } 42 | return ret, nil 43 | } 44 | 45 | func CPUInfo() ([]CPUInfoStat, error) { 46 | filename := "/proc/cpuinfo" 47 | lines, _ := common.ReadLines(filename) 48 | 49 | var ret []CPUInfoStat 50 | 51 | var c CPUInfoStat 52 | for _, line := range lines { 53 | fields := strings.Split(line, ":") 54 | if len(fields) < 2 { 55 | if c.VendorID != "" { 56 | ret = append(ret, c) 57 | } 58 | continue 59 | } 60 | key := strings.TrimSpace(fields[0]) 61 | value := strings.TrimSpace(fields[1]) 62 | 63 | switch key { 64 | case "processor": 65 | c = CPUInfoStat{} 66 | t, err := strconv.ParseInt(value, 10, 64) 67 | if err != nil { 68 | return ret, err 69 | } 70 | c.CPU = int32(t) 71 | case "vendor_id": 72 | c.VendorID = value 73 | case "cpu family": 74 | c.Family = value 75 | case "model": 76 | c.Model = value 77 | case "model name": 78 | c.ModelName = value 79 | case "stepping": 80 | t, err := strconv.ParseInt(value, 10, 64) 81 | if err != nil { 82 | return ret, err 83 | } 84 | c.Stepping = int32(t) 85 | case "cpu MHz": 86 | t, err := strconv.ParseFloat(value, 64) 87 | if err != nil { 88 | return ret, err 89 | } 90 | c.Mhz = t 91 | case "cache size": 92 | t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64) 93 | if err != nil { 94 | return ret, err 95 | } 96 | c.CacheSize = int32(t) 97 | case "physical id": 98 | c.PhysicalID = value 99 | case "core id": 100 | c.CoreID = value 101 | case "cpu cores": 102 | t, err := strconv.ParseInt(value, 10, 64) 103 | if err != nil { 104 | return ret, err 105 | } 106 | c.Cores = int32(t) 107 | case "flags": 108 | c.Flags = strings.Split(value, ",") 109 | } 110 | } 111 | return ret, nil 112 | } 113 | 114 | var CLK_TCK = 100 115 | 116 | func init() { 117 | out, err := exec.Command("getconf", "CLK_TCK").CombinedOutput() 118 | if err == nil { 119 | i, err := strconv.Atoi(strings.TrimSpace(string(out))) 120 | if err == nil { 121 | CLK_TCK = i 122 | } 123 | } 124 | } 125 | 126 | func parseStatLine(line string) (*CPUTimesStat, error) { 127 | fields := strings.Fields(line) 128 | 129 | if strings.HasPrefix(fields[0], "cpu") == false { 130 | // return CPUTimesStat{}, e 131 | return nil, errors.New("not contain cpu") 132 | } 133 | 134 | cpu := fields[0] 135 | if cpu == "cpu" { 136 | cpu = "cpu-total" 137 | } 138 | user, err := strconv.ParseFloat(fields[1], 64) 139 | if err != nil { 140 | return nil, err 141 | } 142 | nice, err := strconv.ParseFloat(fields[2], 64) 143 | if err != nil { 144 | return nil, err 145 | } 146 | system, err := strconv.ParseFloat(fields[3], 64) 147 | if err != nil { 148 | return nil, err 149 | } 150 | idle, err := strconv.ParseFloat(fields[4], 64) 151 | if err != nil { 152 | return nil, err 153 | } 154 | iowait, err := strconv.ParseFloat(fields[5], 64) 155 | if err != nil { 156 | return nil, err 157 | } 158 | irq, err := strconv.ParseFloat(fields[6], 64) 159 | if err != nil { 160 | return nil, err 161 | } 162 | softirq, err := strconv.ParseFloat(fields[7], 64) 163 | if err != nil { 164 | return nil, err 165 | } 166 | stolen, err := strconv.ParseFloat(fields[8], 64) 167 | if err != nil { 168 | return nil, err 169 | } 170 | 171 | cpu_tick := float64(CLK_TCK) 172 | ct := &CPUTimesStat{ 173 | CPU: cpu, 174 | User: float64(user) / cpu_tick, 175 | Nice: float64(nice) / cpu_tick, 176 | System: float64(system) / cpu_tick, 177 | Idle: float64(idle) / cpu_tick, 178 | Iowait: float64(iowait) / cpu_tick, 179 | Irq: float64(irq) / cpu_tick, 180 | Softirq: float64(softirq) / cpu_tick, 181 | Stolen: float64(stolen) / cpu_tick, 182 | } 183 | if len(fields) > 9 { // Linux >= 2.6.11 184 | steal, err := strconv.ParseFloat(fields[9], 64) 185 | if err != nil { 186 | return nil, err 187 | } 188 | ct.Steal = float64(steal) 189 | } 190 | if len(fields) > 10 { // Linux >= 2.6.24 191 | guest, err := strconv.ParseFloat(fields[10], 64) 192 | if err != nil { 193 | return nil, err 194 | } 195 | ct.Guest = float64(guest) 196 | } 197 | if len(fields) > 11 { // Linux >= 3.2.0 198 | guestNice, err := strconv.ParseFloat(fields[11], 64) 199 | if err != nil { 200 | return nil, err 201 | } 202 | ct.GuestNice = float64(guestNice) 203 | } 204 | 205 | return ct, nil 206 | } 207 | --------------------------------------------------------------------------------