parent
e2bc5d80c9
commit
9969c4e810
|
@ -2,7 +2,8 @@
|
|||
|
||||
### Features
|
||||
|
||||
[#158](https://github.com/influxdb/telegraf/pull/158): Apache Plugin
|
||||
[#150](https://github.com/influxdb/telegraf/pull/150): Add Host Uptime metric to system plugin
|
||||
[#158](https://github.com/influxdb/telegraf/pull/158): Apache Plugin. Thanks @KPACHbIuLLIAnO4
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"ImportPath": "github.com/influxdb/telegraf",
|
||||
"GoVersion": "go1.4.2",
|
||||
"GoVersion": "go1.5",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
|
@ -28,6 +28,11 @@
|
|||
"ImportPath": "github.com/cenkalti/backoff",
|
||||
"Rev": "4dc77674aceaabba2c7e3da25d4c823edfb73f99"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudfoundry/gosigar",
|
||||
"Comment": "scotty_09012012-27-g3ed7c74",
|
||||
"Rev": "3ed7c74352dae6dc00bdc8c74045375352e3ec05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/dancannon/gorethink/encoding",
|
||||
"Comment": "v1.x.x-1-g786f12a",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
.vagrant
|
|
@ -0,0 +1,8 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
|
||||
install:
|
||||
- 'go install github.com/onsi/ginkgo/ginkgo'
|
||||
script: 'ginkgo -r'
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,9 @@
|
|||
Copyright (c) [2009-2011] VMware, Inc. All Rights Reserved.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
You may not use this product except in compliance with the License.
|
||||
|
||||
This product includes a number of subcomponents with
|
||||
separate copyright notices and license terms. Your use of these
|
||||
subcomponents is subject to the terms and conditions of the
|
||||
subcomponent's license, as noted in the LICENSE file.
|
|
@ -0,0 +1,22 @@
|
|||
# Go sigar
|
||||
|
||||
## Overview
|
||||
|
||||
Go sigar is a golang implementation of the
|
||||
[sigar API](https://github.com/hyperic/sigar). The Go version of
|
||||
sigar has a very similar interface, but is being written from scratch
|
||||
in pure go/cgo, rather than cgo bindings for libsigar.
|
||||
|
||||
## Test drive
|
||||
|
||||
$ go get github.com/cloudfoundry/gosigar
|
||||
$ cd $GOPATH/src/github.com/cloudfoundry/gosigar/examples
|
||||
$ go run uptime.go
|
||||
|
||||
## Supported platforms
|
||||
|
||||
Currently targeting modern flavors of darwin and linux.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
|
@ -0,0 +1,25 @@
|
|||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.box = "hashicorp/precise64"
|
||||
config.vm.provision "shell", inline: "mkdir -p /home/vagrant/go"
|
||||
config.vm.synced_folder ".", "/home/vagrant/go/src/github.com/cloudfoundry/gosigar"
|
||||
config.vm.provision "shell", inline: "chown -R vagrant:vagrant /home/vagrant/go"
|
||||
install_go = <<-BASH
|
||||
set -e
|
||||
|
||||
if [ ! -d "/usr/local/go" ]; then
|
||||
cd /tmp && wget https://storage.googleapis.com/golang/go1.3.3.linux-amd64.tar.gz
|
||||
cd /usr/local
|
||||
tar xvzf /tmp/go1.3.3.linux-amd64.tar.gz
|
||||
echo 'export GOPATH=/home/vagrant/go; export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin' >> /home/vagrant/.bashrc
|
||||
fi
|
||||
export GOPATH=/home/vagrant/go
|
||||
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
|
||||
/usr/local/go/bin/go get -u github.com/onsi/ginkgo/ginkgo
|
||||
/usr/local/go/bin/go get -u github.com/onsi/gomega;
|
||||
BASH
|
||||
config.vm.provision "shell", inline: 'apt-get install -y git-core'
|
||||
config.vm.provision "shell", inline: install_go
|
||||
end
|
69
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/concrete_sigar.go
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/concrete_sigar.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
package sigar
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ConcreteSigar struct{}
|
||||
|
||||
func (c *ConcreteSigar) CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{}) {
|
||||
// samplesCh is buffered to 1 value to immediately return first CPU sample
|
||||
samplesCh := make(chan Cpu, 1)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
var cpuUsage Cpu
|
||||
|
||||
// Immediately provide non-delta value.
|
||||
// samplesCh is buffered to 1 value, so it will not block.
|
||||
cpuUsage.Get()
|
||||
samplesCh <- cpuUsage
|
||||
|
||||
ticker := time.NewTicker(collectionInterval)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
previousCpuUsage := cpuUsage
|
||||
|
||||
cpuUsage.Get()
|
||||
|
||||
select {
|
||||
case samplesCh <- cpuUsage.Delta(previousCpuUsage):
|
||||
default:
|
||||
// Include default to avoid channel blocking
|
||||
}
|
||||
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return samplesCh, stopCh
|
||||
}
|
||||
|
||||
func (c *ConcreteSigar) GetLoadAverage() (LoadAverage, error) {
|
||||
l := LoadAverage{}
|
||||
err := l.Get()
|
||||
return l, err
|
||||
}
|
||||
|
||||
func (c *ConcreteSigar) GetMem() (Mem, error) {
|
||||
m := Mem{}
|
||||
err := m.Get()
|
||||
return m, err
|
||||
}
|
||||
|
||||
func (c *ConcreteSigar) GetSwap() (Swap, error) {
|
||||
s := Swap{}
|
||||
err := s.Get()
|
||||
return s, err
|
||||
}
|
||||
|
||||
func (c *ConcreteSigar) GetFileSystemUsage(path string) (FileSystemUsage, error) {
|
||||
f := FileSystemUsage{}
|
||||
err := f.Get(path)
|
||||
return f, err
|
||||
}
|
85
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/concrete_sigar_test.go
generated
vendored
Normal file
85
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/concrete_sigar_test.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
package sigar_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
sigar "github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
var _ = Describe("ConcreteSigar", func() {
|
||||
var concreteSigar *sigar.ConcreteSigar
|
||||
|
||||
BeforeEach(func() {
|
||||
concreteSigar = &sigar.ConcreteSigar{}
|
||||
})
|
||||
|
||||
Describe("CollectCpuStats", func() {
|
||||
It("immediately makes first CPU usage available even though it's not very accurate", func() {
|
||||
samplesCh, stop := concreteSigar.CollectCpuStats(500 * time.Millisecond)
|
||||
|
||||
firstValue := <-samplesCh
|
||||
Expect(firstValue.User).To(BeNumerically(">", 0))
|
||||
|
||||
stop <- struct{}{}
|
||||
})
|
||||
|
||||
It("makes CPU usage delta values available", func() {
|
||||
samplesCh, stop := concreteSigar.CollectCpuStats(500 * time.Millisecond)
|
||||
|
||||
firstValue := <-samplesCh
|
||||
|
||||
secondValue := <-samplesCh
|
||||
Expect(secondValue.User).To(BeNumerically("<", firstValue.User))
|
||||
|
||||
stop <- struct{}{}
|
||||
})
|
||||
|
||||
It("does not block", func() {
|
||||
_, stop := concreteSigar.CollectCpuStats(10 * time.Millisecond)
|
||||
|
||||
// Sleep long enough for samplesCh to fill at least 2 values
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
stop <- struct{}{}
|
||||
|
||||
// If CollectCpuStats blocks it will never get here
|
||||
Expect(true).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
It("GetLoadAverage", func() {
|
||||
avg, err := concreteSigar.GetLoadAverage()
|
||||
Expect(avg.One).ToNot(BeNil())
|
||||
Expect(avg.Five).ToNot(BeNil())
|
||||
Expect(avg.Fifteen).ToNot(BeNil())
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("GetMem", func() {
|
||||
mem, err := concreteSigar.GetMem()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(mem.Total).To(BeNumerically(">", 0))
|
||||
Expect(mem.Used + mem.Free).To(BeNumerically("<=", mem.Total))
|
||||
})
|
||||
|
||||
It("GetSwap", func() {
|
||||
swap, err := concreteSigar.GetSwap()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(swap.Used + swap.Free).To(BeNumerically("<=", swap.Total))
|
||||
})
|
||||
|
||||
It("GetSwap", func() {
|
||||
fsusage, err := concreteSigar.GetFileSystemUsage("/")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(fsusage.Total).ToNot(BeNil())
|
||||
|
||||
fsusage, err = concreteSigar.GetFileSystemUsage("T O T A L L Y B O G U S")
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(fsusage.Total).To(Equal(uint64(0)))
|
||||
})
|
||||
})
|
52
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/cputimes.go
generated
vendored
Normal file
52
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/cputimes.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cpus := sigar.CpuList{}
|
||||
cpus.Get()
|
||||
tcpu := getOverallCpu(cpus)
|
||||
|
||||
for i, cpu := range cpus.List {
|
||||
fmt.Printf("CPU%d Ticks: %d\n", i, cpu.Total())
|
||||
}
|
||||
|
||||
fmt.Printf("Total CPU Ticks: %d\n", tcpu.Total())
|
||||
fmt.Printf("Total CPU Time: %d\n", tcpu.Total()/128)
|
||||
fmt.Printf("User CPU Time: %d\n", tcpu.User/128)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
tcpu2 := sigar.Cpu{}
|
||||
tcpu2.Get()
|
||||
|
||||
dcpu := tcpu2.Delta(tcpu)
|
||||
tcpuDelta := tcpu2.Total() - tcpu.Total()
|
||||
iPercentage := 100.0 * float64(dcpu.Idle) / float64(tcpuDelta)
|
||||
fmt.Printf("Idle percentage: %f\n", iPercentage)
|
||||
bPercentage := 100.0 * float64(busy(tcpu2)-busy(tcpu)) / float64(tcpuDelta)
|
||||
fmt.Printf("Busy percentage: %f\n", bPercentage)
|
||||
}
|
||||
|
||||
func busy(c sigar.Cpu) uint64 {
|
||||
return c.Total() - c.Idle
|
||||
}
|
||||
|
||||
func getOverallCpu(cl sigar.CpuList) sigar.Cpu {
|
||||
var overallCpu sigar.Cpu
|
||||
for _, c := range cl.List {
|
||||
overallCpu.User += c.User
|
||||
overallCpu.Nice += c.Nice
|
||||
overallCpu.Sys += c.Sys
|
||||
overallCpu.Idle += c.Idle
|
||||
overallCpu.Wait += c.Wait
|
||||
overallCpu.Irq += c.Irq
|
||||
overallCpu.SoftIrq += c.SoftIrq
|
||||
overallCpu.Stolen += c.Stolen
|
||||
}
|
||||
return overallCpu
|
||||
}
|
39
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/df.go
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/df.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
"os"
|
||||
)
|
||||
|
||||
const output_format = "%-15s %4s %4s %5s %4s %-15s\n"
|
||||
|
||||
func formatSize(size uint64) string {
|
||||
return sigar.FormatSize(size * 1024)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fslist := sigar.FileSystemList{}
|
||||
fslist.Get()
|
||||
|
||||
fmt.Fprintf(os.Stdout, output_format,
|
||||
"Filesystem", "Size", "Used", "Avail", "Use%", "Mounted on")
|
||||
|
||||
for _, fs := range fslist.List {
|
||||
dir_name := fs.DirName
|
||||
|
||||
usage := sigar.FileSystemUsage{}
|
||||
|
||||
usage.Get(dir_name)
|
||||
|
||||
fmt.Fprintf(os.Stdout, output_format,
|
||||
fs.DevName,
|
||||
formatSize(usage.Total),
|
||||
formatSize(usage.Used),
|
||||
formatSize(usage.Avail),
|
||||
sigar.FormatPercent(usage.UsePercent()),
|
||||
dir_name)
|
||||
}
|
||||
}
|
33
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/free.go
generated
vendored
Normal file
33
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/free.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
"os"
|
||||
)
|
||||
|
||||
func format(val uint64) uint64 {
|
||||
return val / 1024
|
||||
}
|
||||
|
||||
func main() {
|
||||
mem := sigar.Mem{}
|
||||
swap := sigar.Swap{}
|
||||
|
||||
mem.Get()
|
||||
swap.Get()
|
||||
|
||||
fmt.Fprintf(os.Stdout, "%18s %10s %10s\n",
|
||||
"total", "used", "free")
|
||||
|
||||
fmt.Fprintf(os.Stdout, "Mem: %10d %10d %10d\n",
|
||||
format(mem.Total), format(mem.Used), format(mem.Free))
|
||||
|
||||
fmt.Fprintf(os.Stdout, "-/+ buffers/cache: %10d %10d\n",
|
||||
format(mem.ActualUsed), format(mem.ActualFree))
|
||||
|
||||
fmt.Fprintf(os.Stdout, "Swap: %10d %10d %10d\n",
|
||||
format(swap.Total), format(swap.Used), format(swap.Free))
|
||||
}
|
37
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/ps.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/ps.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pids := sigar.ProcList{}
|
||||
pids.Get()
|
||||
|
||||
// ps -eo pid,ppid,stime,time,rss,state,comm
|
||||
fmt.Print(" PID PPID STIME TIME RSS S COMMAND\n")
|
||||
|
||||
for _, pid := range pids.List {
|
||||
state := sigar.ProcState{}
|
||||
mem := sigar.ProcMem{}
|
||||
time := sigar.ProcTime{}
|
||||
|
||||
if err := state.Get(pid); err != nil {
|
||||
continue
|
||||
}
|
||||
if err := mem.Get(pid); err != nil {
|
||||
continue
|
||||
}
|
||||
if err := time.Get(pid); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("%5d %5d %s %s %6d %c %s\n",
|
||||
pid, state.Ppid,
|
||||
time.FormatStartTime(), time.FormatTotal(),
|
||||
mem.Resident/1024, state.State, state.Name)
|
||||
}
|
||||
}
|
27
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/uptime.go
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/examples/uptime.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
concreteSigar := sigar.ConcreteSigar{}
|
||||
|
||||
uptime := sigar.Uptime{}
|
||||
uptime.Get()
|
||||
avg, err := concreteSigar.GetLoadAverage()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get load average")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stdout, " %s up %s load average: %.2f, %.2f, %.2f\n",
|
||||
time.Now().Format("15:04:05"),
|
||||
uptime.Format(),
|
||||
avg.One, avg.Five, avg.Fifteen)
|
||||
}
|
72
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/fakes/fake_sigar.go
generated
vendored
Normal file
72
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/fakes/fake_sigar.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
package fakes
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sigar "github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
type FakeSigar struct {
|
||||
LoadAverage sigar.LoadAverage
|
||||
LoadAverageErr error
|
||||
|
||||
Mem sigar.Mem
|
||||
MemErr error
|
||||
|
||||
Swap sigar.Swap
|
||||
SwapErr error
|
||||
|
||||
FileSystemUsage sigar.FileSystemUsage
|
||||
FileSystemUsageErr error
|
||||
FileSystemUsagePath string
|
||||
|
||||
CollectCpuStatsCpuCh chan sigar.Cpu
|
||||
CollectCpuStatsStopCh chan struct{}
|
||||
}
|
||||
|
||||
func NewFakeSigar() *FakeSigar {
|
||||
return &FakeSigar{
|
||||
CollectCpuStatsCpuCh: make(chan sigar.Cpu, 1),
|
||||
CollectCpuStatsStopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FakeSigar) CollectCpuStats(collectionInterval time.Duration) (<-chan sigar.Cpu, chan<- struct{}) {
|
||||
samplesCh := make(chan sigar.Cpu, 1)
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case cpuStat := <-f.CollectCpuStatsCpuCh:
|
||||
select {
|
||||
case samplesCh <- cpuStat:
|
||||
default:
|
||||
// Include default to avoid channel blocking
|
||||
}
|
||||
|
||||
case <-f.CollectCpuStatsStopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return samplesCh, stopCh
|
||||
}
|
||||
|
||||
func (f *FakeSigar) GetLoadAverage() (sigar.LoadAverage, error) {
|
||||
return f.LoadAverage, f.LoadAverageErr
|
||||
}
|
||||
|
||||
func (f *FakeSigar) GetMem() (sigar.Mem, error) {
|
||||
return f.Mem, f.MemErr
|
||||
}
|
||||
|
||||
func (f *FakeSigar) GetSwap() (sigar.Swap, error) {
|
||||
return f.Swap, f.SwapErr
|
||||
}
|
||||
|
||||
func (f *FakeSigar) GetFileSystemUsage(path string) (sigar.FileSystemUsage, error) {
|
||||
f.FileSystemUsagePath = path
|
||||
return f.FileSystemUsage, f.FileSystemUsageErr
|
||||
}
|
50
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/README.md
generated
vendored
Normal file
50
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/README.md
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Process notifications for Go
|
||||
|
||||
## Overview
|
||||
|
||||
The psnotify package captures process events from the kernel via
|
||||
kqueue on Darwin/BSD and the netlink connector on Linux.
|
||||
|
||||
The psnotify API is similar to the
|
||||
[fsnotify](https://github.com/howeyc/fsnotify) package.
|
||||
|
||||
Example:
|
||||
```go
|
||||
watcher, err := psnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Process events
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-watcher.Fork:
|
||||
log.Println("fork event:", ev)
|
||||
case ev := <-watcher.Exec:
|
||||
log.Println("exec event:", ev)
|
||||
case ev := <-watcher.Exit:
|
||||
log.Println("exit event:", ev)
|
||||
case err := <-watcher.Error:
|
||||
log.Println("error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = watcher.Watch(os.Getpid(), psnotify.PROC_EVENT_ALL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/* ... do stuff ... */
|
||||
watcher.Close()
|
||||
```
|
||||
|
||||
## Supported platforms
|
||||
|
||||
Currently targeting modern flavors of Darwin and Linux.
|
||||
Should work on BSD, but untested.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
136
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify.go
generated
vendored
Normal file
136
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify.go
generated
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package psnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ProcEventFork struct {
|
||||
ParentPid int // Pid of the process that called fork()
|
||||
ChildPid int // Child process pid created by fork()
|
||||
}
|
||||
|
||||
type ProcEventExec struct {
|
||||
Pid int // Pid of the process that called exec()
|
||||
}
|
||||
|
||||
type ProcEventExit struct {
|
||||
Pid int // Pid of the process that called exit()
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
flags uint32 // Saved value of Watch() flags param
|
||||
}
|
||||
|
||||
type eventListener interface {
|
||||
close() error // Watch.Close() closes the OS specific listener
|
||||
}
|
||||
|
||||
type Watcher struct {
|
||||
listener eventListener // OS specifics (kqueue or netlink)
|
||||
watches map[int]*watch // Map of watched process ids
|
||||
Error chan error // Errors are sent on this channel
|
||||
Fork chan *ProcEventFork // Fork events are sent on this channel
|
||||
Exec chan *ProcEventExec // Exec events are sent on this channel
|
||||
Exit chan *ProcEventExit // Exit events are sent on this channel
|
||||
done chan bool // Used to stop the readEvents() goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
// Initialize event listener and channels
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
listener, err := createListener()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
listener: listener,
|
||||
watches: make(map[int]*watch),
|
||||
Fork: make(chan *ProcEventFork),
|
||||
Exec: make(chan *ProcEventExec),
|
||||
Exit: make(chan *ProcEventExit),
|
||||
Error: make(chan error),
|
||||
done: make(chan bool, 1),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close event channels when done message is received
|
||||
func (w *Watcher) finish() {
|
||||
close(w.Fork)
|
||||
close(w.Exec)
|
||||
close(w.Exit)
|
||||
close(w.Error)
|
||||
}
|
||||
|
||||
// Closes the OS specific event listener,
|
||||
// removes all watches and closes all event channels.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
for pid := range w.watches {
|
||||
w.RemoveWatch(pid)
|
||||
}
|
||||
|
||||
w.done <- true
|
||||
|
||||
w.listener.close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add pid to the watched process set.
|
||||
// The flags param is a bitmask of process events to capture,
|
||||
// must be one or more of: PROC_EVENT_FORK, PROC_EVENT_EXEC, PROC_EVENT_EXIT
|
||||
func (w *Watcher) Watch(pid int, flags uint32) error {
|
||||
if w.isClosed {
|
||||
return errors.New("psnotify watcher is closed")
|
||||
}
|
||||
|
||||
watchEntry, found := w.watches[pid]
|
||||
|
||||
if found {
|
||||
watchEntry.flags |= flags
|
||||
} else {
|
||||
if err := w.register(pid, flags); err != nil {
|
||||
return err
|
||||
}
|
||||
w.watches[pid] = &watch{flags: flags}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove pid from the watched process set.
|
||||
func (w *Watcher) RemoveWatch(pid int) error {
|
||||
_, ok := w.watches[pid]
|
||||
if !ok {
|
||||
msg := fmt.Sprintf("watch for pid=%d does not exist", pid)
|
||||
return errors.New(msg)
|
||||
}
|
||||
delete(w.watches, pid)
|
||||
return w.unregister(pid)
|
||||
}
|
||||
|
||||
// Internal helper to check if there is a message on the "done" channel.
|
||||
// The "done" message is sent by the Close() method; when received here,
|
||||
// the Watcher.finish method is called to close all channels and return
|
||||
// true - in which case the caller should break from the readEvents loop.
|
||||
func (w *Watcher) isDone() bool {
|
||||
var done bool
|
||||
select {
|
||||
case done = <-w.done:
|
||||
w.finish()
|
||||
default:
|
||||
}
|
||||
return done
|
||||
}
|
93
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_bsd.go
generated
vendored
Normal file
93
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
// +build darwin freebsd netbsd openbsd
|
||||
|
||||
// Go interface to BSD kqueue process events.
|
||||
package psnotify
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
// Flags (from <sys/event.h>)
|
||||
PROC_EVENT_FORK = syscall.NOTE_FORK // fork() events
|
||||
PROC_EVENT_EXEC = syscall.NOTE_EXEC // exec() events
|
||||
PROC_EVENT_EXIT = syscall.NOTE_EXIT // exit() events
|
||||
|
||||
// Watch for all process events
|
||||
PROC_EVENT_ALL = PROC_EVENT_FORK | PROC_EVENT_EXEC | PROC_EVENT_EXIT
|
||||
)
|
||||
|
||||
type kqueueListener struct {
|
||||
kq int // The syscall.Kqueue() file descriptor
|
||||
buf [1]syscall.Kevent_t // An event buffer for Add/Remove watch
|
||||
}
|
||||
|
||||
// Initialize bsd implementation of the eventListener interface
|
||||
func createListener() (eventListener, error) {
|
||||
listener := &kqueueListener{}
|
||||
kq, err := syscall.Kqueue()
|
||||
listener.kq = kq
|
||||
return listener, err
|
||||
}
|
||||
|
||||
// Initialize Kevent_t fields and propagate changelist for the given pid
|
||||
func (w *Watcher) kevent(pid int, fflags uint32, flags int) error {
|
||||
listener, _ := w.listener.(*kqueueListener)
|
||||
event := &listener.buf[0]
|
||||
|
||||
syscall.SetKevent(event, pid, syscall.EVFILT_PROC, flags)
|
||||
event.Fflags = fflags
|
||||
|
||||
_, err := syscall.Kevent(listener.kq, listener.buf[:], nil, nil)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete filter for given pid from the queue
|
||||
func (w *Watcher) unregister(pid int) error {
|
||||
return w.kevent(pid, 0, syscall.EV_DELETE)
|
||||
}
|
||||
|
||||
// Add and enable filter for given pid in the queue
|
||||
func (w *Watcher) register(pid int, flags uint32) error {
|
||||
return w.kevent(pid, flags, syscall.EV_ADD|syscall.EV_ENABLE)
|
||||
}
|
||||
|
||||
// Poll the kqueue file descriptor and dispatch to the Event channels
|
||||
func (w *Watcher) readEvents() {
|
||||
listener, _ := w.listener.(*kqueueListener)
|
||||
events := make([]syscall.Kevent_t, 10)
|
||||
|
||||
for {
|
||||
if w.isDone() {
|
||||
return
|
||||
}
|
||||
|
||||
n, err := syscall.Kevent(listener.kq, nil, events, nil)
|
||||
if err != nil {
|
||||
w.Error <- err
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ev := range events[:n] {
|
||||
pid := int(ev.Ident)
|
||||
|
||||
switch ev.Fflags {
|
||||
case syscall.NOTE_FORK:
|
||||
w.Fork <- &ProcEventFork{ParentPid: pid}
|
||||
case syscall.NOTE_EXEC:
|
||||
w.Exec <- &ProcEventExec{Pid: pid}
|
||||
case syscall.NOTE_EXIT:
|
||||
w.RemoveWatch(pid)
|
||||
w.Exit <- &ProcEventExit{Pid: pid}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close our kqueue file descriptor; deletes any remaining filters
|
||||
func (listener *kqueueListener) close() error {
|
||||
return syscall.Close(listener.kq)
|
||||
}
|
253
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_linux.go
generated
vendored
Normal file
253
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
// Go interface to the Linux netlink process connector.
|
||||
// See Documentation/connector/connector.txt in the linux kernel source tree.
|
||||
package psnotify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
// internal flags (from <linux/connector.h>)
|
||||
_CN_IDX_PROC = 0x1
|
||||
_CN_VAL_PROC = 0x1
|
||||
|
||||
// internal flags (from <linux/cn_proc.h>)
|
||||
_PROC_CN_MCAST_LISTEN = 1
|
||||
_PROC_CN_MCAST_IGNORE = 2
|
||||
|
||||
// Flags (from <linux/cn_proc.h>)
|
||||
PROC_EVENT_FORK = 0x00000001 // fork() events
|
||||
PROC_EVENT_EXEC = 0x00000002 // exec() events
|
||||
PROC_EVENT_EXIT = 0x80000000 // exit() events
|
||||
|
||||
// Watch for all process events
|
||||
PROC_EVENT_ALL = PROC_EVENT_FORK | PROC_EVENT_EXEC | PROC_EVENT_EXIT
|
||||
)
|
||||
|
||||
var (
|
||||
byteOrder = binary.LittleEndian
|
||||
)
|
||||
|
||||
// linux/connector.h: struct cb_id
|
||||
type cbId struct {
|
||||
Idx uint32
|
||||
Val uint32
|
||||
}
|
||||
|
||||
// linux/connector.h: struct cb_msg
|
||||
type cnMsg struct {
|
||||
Id cbId
|
||||
Seq uint32
|
||||
Ack uint32
|
||||
Len uint16
|
||||
Flags uint16
|
||||
}
|
||||
|
||||
// linux/cn_proc.h: struct proc_event.{what,cpu,timestamp_ns}
|
||||
type procEventHeader struct {
|
||||
What uint32
|
||||
Cpu uint32
|
||||
Timestamp uint64
|
||||
}
|
||||
|
||||
// linux/cn_proc.h: struct proc_event.fork
|
||||
type forkProcEvent struct {
|
||||
ParentPid uint32
|
||||
ParentTgid uint32
|
||||
ChildPid uint32
|
||||
ChildTgid uint32
|
||||
}
|
||||
|
||||
// linux/cn_proc.h: struct proc_event.exec
|
||||
type execProcEvent struct {
|
||||
ProcessPid uint32
|
||||
ProcessTgid uint32
|
||||
}
|
||||
|
||||
// linux/cn_proc.h: struct proc_event.exit
|
||||
type exitProcEvent struct {
|
||||
ProcessPid uint32
|
||||
ProcessTgid uint32
|
||||
ExitCode uint32
|
||||
ExitSignal uint32
|
||||
}
|
||||
|
||||
// standard netlink header + connector header
|
||||
type netlinkProcMessage struct {
|
||||
Header syscall.NlMsghdr
|
||||
Data cnMsg
|
||||
}
|
||||
|
||||
type netlinkListener struct {
|
||||
addr *syscall.SockaddrNetlink // Netlink socket address
|
||||
sock int // The syscall.Socket() file descriptor
|
||||
seq uint32 // struct cn_msg.seq
|
||||
}
|
||||
|
||||
// Initialize linux implementation of the eventListener interface
|
||||
func createListener() (eventListener, error) {
|
||||
listener := &netlinkListener{}
|
||||
err := listener.bind()
|
||||
return listener, err
|
||||
}
|
||||
|
||||
// noop on linux
|
||||
func (w *Watcher) unregister(pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// noop on linux
|
||||
func (w *Watcher) register(pid int, flags uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read events from the netlink socket
|
||||
func (w *Watcher) readEvents() {
|
||||
buf := make([]byte, syscall.Getpagesize())
|
||||
|
||||
listener, _ := w.listener.(*netlinkListener)
|
||||
|
||||
for {
|
||||
if w.isDone() {
|
||||
return
|
||||
}
|
||||
|
||||
nr, _, err := syscall.Recvfrom(listener.sock, buf, 0)
|
||||
|
||||
if err != nil {
|
||||
w.Error <- err
|
||||
continue
|
||||
}
|
||||
if nr < syscall.NLMSG_HDRLEN {
|
||||
w.Error <- syscall.EINVAL
|
||||
continue
|
||||
}
|
||||
|
||||
msgs, _ := syscall.ParseNetlinkMessage(buf[:nr])
|
||||
|
||||
for _, m := range msgs {
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
w.handleEvent(m.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Internal helper to check if pid && event is being watched
|
||||
func (w *Watcher) isWatching(pid int, event uint32) bool {
|
||||
if watch, ok := w.watches[pid]; ok {
|
||||
return (watch.flags & event) == event
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Dispatch events from the netlink socket to the Event channels.
|
||||
// Unlike bsd kqueue, netlink receives events for all pids,
|
||||
// so we apply filtering based on the watch table via isWatching()
|
||||
func (w *Watcher) handleEvent(data []byte) {
|
||||
buf := bytes.NewBuffer(data)
|
||||
msg := &cnMsg{}
|
||||
hdr := &procEventHeader{}
|
||||
|
||||
binary.Read(buf, byteOrder, msg)
|
||||
binary.Read(buf, byteOrder, hdr)
|
||||
|
||||
switch hdr.What {
|
||||
case PROC_EVENT_FORK:
|
||||
event := &forkProcEvent{}
|
||||
binary.Read(buf, byteOrder, event)
|
||||
ppid := int(event.ParentTgid)
|
||||
pid := int(event.ChildTgid)
|
||||
|
||||
if w.isWatching(ppid, PROC_EVENT_EXEC) {
|
||||
// follow forks
|
||||
watch, _ := w.watches[ppid]
|
||||
w.Watch(pid, watch.flags)
|
||||
}
|
||||
|
||||
if w.isWatching(ppid, PROC_EVENT_FORK) {
|
||||
w.Fork <- &ProcEventFork{ParentPid: ppid, ChildPid: pid}
|
||||
}
|
||||
case PROC_EVENT_EXEC:
|
||||
event := &execProcEvent{}
|
||||
binary.Read(buf, byteOrder, event)
|
||||
pid := int(event.ProcessTgid)
|
||||
|
||||
if w.isWatching(pid, PROC_EVENT_EXEC) {
|
||||
w.Exec <- &ProcEventExec{Pid: pid}
|
||||
}
|
||||
case PROC_EVENT_EXIT:
|
||||
event := &exitProcEvent{}
|
||||
binary.Read(buf, byteOrder, event)
|
||||
pid := int(event.ProcessTgid)
|
||||
|
||||
if w.isWatching(pid, PROC_EVENT_EXIT) {
|
||||
w.RemoveWatch(pid)
|
||||
w.Exit <- &ProcEventExit{Pid: pid}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind our netlink socket and
|
||||
// send a listen control message to the connector driver.
|
||||
func (listener *netlinkListener) bind() error {
|
||||
sock, err := syscall.Socket(
|
||||
syscall.AF_NETLINK,
|
||||
syscall.SOCK_DGRAM,
|
||||
syscall.NETLINK_CONNECTOR)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listener.sock = sock
|
||||
listener.addr = &syscall.SockaddrNetlink{
|
||||
Family: syscall.AF_NETLINK,
|
||||
Groups: _CN_IDX_PROC,
|
||||
}
|
||||
|
||||
err = syscall.Bind(listener.sock, listener.addr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return listener.send(_PROC_CN_MCAST_LISTEN)
|
||||
}
|
||||
|
||||
// Send an ignore control message to the connector driver
|
||||
// and close our netlink socket.
|
||||
func (listener *netlinkListener) close() error {
|
||||
err := listener.send(_PROC_CN_MCAST_IGNORE)
|
||||
syscall.Close(listener.sock)
|
||||
return err
|
||||
}
|
||||
|
||||
// Generic method for sending control messages to the connector
|
||||
// driver; where op is one of PROC_CN_MCAST_{LISTEN,IGNORE}
|
||||
func (listener *netlinkListener) send(op uint32) error {
|
||||
listener.seq++
|
||||
pr := &netlinkProcMessage{}
|
||||
plen := binary.Size(pr.Data) + binary.Size(op)
|
||||
pr.Header.Len = syscall.NLMSG_HDRLEN + uint32(plen)
|
||||
pr.Header.Type = uint16(syscall.NLMSG_DONE)
|
||||
pr.Header.Flags = 0
|
||||
pr.Header.Seq = listener.seq
|
||||
pr.Header.Pid = uint32(os.Getpid())
|
||||
|
||||
pr.Data.Id.Idx = _CN_IDX_PROC
|
||||
pr.Data.Id.Val = _CN_VAL_PROC
|
||||
|
||||
pr.Data.Len = uint16(binary.Size(op))
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, pr.Header.Len))
|
||||
binary.Write(buf, byteOrder, pr)
|
||||
binary.Write(buf, byteOrder, op)
|
||||
|
||||
return syscall.Sendto(listener.sock, buf.Bytes(), 0, listener.addr)
|
||||
}
|
283
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_test.go
generated
vendored
Normal file
283
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/psnotify/psnotify_test.go
generated
vendored
Normal file
|
@ -0,0 +1,283 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package psnotify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type anyEvent struct {
|
||||
exits []int
|
||||
forks []int
|
||||
execs []int
|
||||
errors []error
|
||||
done chan bool
|
||||
}
|
||||
|
||||
type testWatcher struct {
|
||||
t *testing.T
|
||||
watcher *Watcher
|
||||
events *anyEvent
|
||||
}
|
||||
|
||||
// General purpose Watcher wrapper for all tests
|
||||
func newTestWatcher(t *testing.T) *testWatcher {
|
||||
watcher, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
events := &anyEvent{
|
||||
done: make(chan bool, 1),
|
||||
}
|
||||
|
||||
tw := &testWatcher{
|
||||
t: t,
|
||||
watcher: watcher,
|
||||
events: events,
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-events.done:
|
||||
return
|
||||
case ev := <-watcher.Fork:
|
||||
events.forks = append(events.forks, ev.ParentPid)
|
||||
case ev := <-watcher.Exec:
|
||||
events.execs = append(events.execs, ev.Pid)
|
||||
case ev := <-watcher.Exit:
|
||||
events.exits = append(events.exits, ev.Pid)
|
||||
case err := <-watcher.Error:
|
||||
events.errors = append(events.errors, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return tw
|
||||
}
|
||||
|
||||
func (tw *testWatcher) close() {
|
||||
pause := 100 * time.Millisecond
|
||||
time.Sleep(pause)
|
||||
|
||||
tw.events.done <- true
|
||||
|
||||
tw.watcher.Close()
|
||||
|
||||
time.Sleep(pause)
|
||||
}
|
||||
|
||||
func skipTest(t *testing.T) bool {
|
||||
if runtime.GOOS == "linux" && os.Getuid() != 0 {
|
||||
fmt.Println("SKIP: test must be run as root on linux")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func startSleepCommand(t *testing.T) *exec.Cmd {
|
||||
cmd := exec.Command("sh", "-c", "sleep 100")
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCommand(t *testing.T, name string) *exec.Cmd {
|
||||
cmd := exec.Command(name)
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func expectEvents(t *testing.T, num int, name string, pids []int) bool {
|
||||
if len(pids) != num {
|
||||
t.Errorf("Expected %d %s events, got=%v", num, name, pids)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func expectEventPid(t *testing.T, name string, expect int, pid int) bool {
|
||||
if expect != pid {
|
||||
t.Errorf("Expected %s pid=%d, received=%d", name, expect, pid)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestWatchFork(t *testing.T) {
|
||||
if skipTest(t) {
|
||||
return
|
||||
}
|
||||
|
||||
pid := os.Getpid()
|
||||
|
||||
tw := newTestWatcher(t)
|
||||
|
||||
// no watches added yet, so this fork event will no be captured
|
||||
runCommand(t, "date")
|
||||
|
||||
// watch fork events for this process
|
||||
if err := tw.watcher.Watch(pid, PROC_EVENT_FORK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// this fork event will be captured,
|
||||
// the exec and exit events will not be captured
|
||||
runCommand(t, "cal")
|
||||
|
||||
tw.close()
|
||||
|
||||
if expectEvents(t, 1, "forks", tw.events.forks) {
|
||||
expectEventPid(t, "fork", pid, tw.events.forks[0])
|
||||
}
|
||||
|
||||
expectEvents(t, 0, "execs", tw.events.execs)
|
||||
expectEvents(t, 0, "exits", tw.events.exits)
|
||||
}
|
||||
|
||||
func TestWatchExit(t *testing.T) {
|
||||
if skipTest(t) {
|
||||
return
|
||||
}
|
||||
|
||||
tw := newTestWatcher(t)
|
||||
|
||||
cmd := startSleepCommand(t)
|
||||
|
||||
childPid := cmd.Process.Pid
|
||||
|
||||
// watch for exit event of our child process
|
||||
if err := tw.watcher.Watch(childPid, PROC_EVENT_EXIT); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// kill our child process, triggers exit event
|
||||
syscall.Kill(childPid, syscall.SIGTERM)
|
||||
|
||||
cmd.Wait()
|
||||
|
||||
tw.close()
|
||||
|
||||
expectEvents(t, 0, "forks", tw.events.forks)
|
||||
|
||||
expectEvents(t, 0, "execs", tw.events.execs)
|
||||
|
||||
if expectEvents(t, 1, "exits", tw.events.exits) {
|
||||
expectEventPid(t, "exit", childPid, tw.events.exits[0])
|
||||
}
|
||||
}
|
||||
|
||||
// combined version of TestWatchFork() and TestWatchExit()
|
||||
func TestWatchForkAndExit(t *testing.T) {
|
||||
if skipTest(t) {
|
||||
return
|
||||
}
|
||||
|
||||
pid := os.Getpid()
|
||||
|
||||
tw := newTestWatcher(t)
|
||||
|
||||
if err := tw.watcher.Watch(pid, PROC_EVENT_FORK); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cmd := startSleepCommand(t)
|
||||
|
||||
childPid := cmd.Process.Pid
|
||||
|
||||
if err := tw.watcher.Watch(childPid, PROC_EVENT_EXIT); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
syscall.Kill(childPid, syscall.SIGTERM)
|
||||
|
||||
cmd.Wait()
|
||||
|
||||
tw.close()
|
||||
|
||||
if expectEvents(t, 1, "forks", tw.events.forks) {
|
||||
expectEventPid(t, "fork", pid, tw.events.forks[0])
|
||||
}
|
||||
|
||||
expectEvents(t, 0, "execs", tw.events.execs)
|
||||
|
||||
if expectEvents(t, 1, "exits", tw.events.exits) {
|
||||
expectEventPid(t, "exit", childPid, tw.events.exits[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatchFollowFork(t *testing.T) {
|
||||
if skipTest(t) {
|
||||
return
|
||||
}
|
||||
|
||||
// Darwin is not able to follow forks, as the kqueue fork event
|
||||
// does not provide the child pid.
|
||||
if runtime.GOOS != "linux" {
|
||||
fmt.Println("SKIP: test follow forks is linux only")
|
||||
return
|
||||
}
|
||||
|
||||
pid := os.Getpid()
|
||||
|
||||
tw := newTestWatcher(t)
|
||||
|
||||
// watch for all process events related to this process
|
||||
if err := tw.watcher.Watch(pid, PROC_EVENT_ALL); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
commands := []string{"date", "cal"}
|
||||
childPids := make([]int, len(commands))
|
||||
|
||||
// triggers fork/exec/exit events for each command
|
||||
for i, name := range commands {
|
||||
cmd := runCommand(t, name)
|
||||
childPids[i] = cmd.Process.Pid
|
||||
}
|
||||
|
||||
// remove watch for this process
|
||||
tw.watcher.RemoveWatch(pid)
|
||||
|
||||
// run commands again to make sure we don't receive any unwanted events
|
||||
for _, name := range commands {
|
||||
runCommand(t, name)
|
||||
}
|
||||
|
||||
tw.close()
|
||||
|
||||
// run commands again to make sure nothing panics after
|
||||
// closing the watcher
|
||||
for _, name := range commands {
|
||||
runCommand(t, name)
|
||||
}
|
||||
|
||||
num := len(commands)
|
||||
if expectEvents(t, num, "forks", tw.events.forks) {
|
||||
for _, epid := range tw.events.forks {
|
||||
expectEventPid(t, "fork", pid, epid)
|
||||
}
|
||||
}
|
||||
|
||||
if expectEvents(t, num, "execs", tw.events.execs) {
|
||||
for i, epid := range tw.events.execs {
|
||||
expectEventPid(t, "exec", childPids[i], epid)
|
||||
}
|
||||
}
|
||||
|
||||
if expectEvents(t, num, "exits", tw.events.exits) {
|
||||
for i, epid := range tw.events.exits {
|
||||
expectEventPid(t, "exit", childPids[i], epid)
|
||||
}
|
||||
}
|
||||
}
|
467
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_darwin.go
generated
vendored
Normal file
467
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,467 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package sigar
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/host_info.h>
|
||||
#include <libproc.h>
|
||||
#include <mach/processor_info.h>
|
||||
#include <mach/vm_map.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (self *LoadAverage) Get() error {
|
||||
avg := []C.double{0, 0, 0}
|
||||
|
||||
C.getloadavg(&avg[0], C.int(len(avg)))
|
||||
|
||||
self.One = float64(avg[0])
|
||||
self.Five = float64(avg[1])
|
||||
self.Fifteen = float64(avg[2])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Uptime) Get() error {
|
||||
tv := syscall.Timeval32{}
|
||||
|
||||
if err := sysctlbyname("kern.boottime", &tv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Mem) Get() error {
|
||||
var vmstat C.vm_statistics_data_t
|
||||
|
||||
if err := sysctlbyname("hw.memsize", &self.Total); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := vm_info(&vmstat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kern := uint64(vmstat.inactive_count) << 12
|
||||
self.Free = uint64(vmstat.free_count) << 12
|
||||
|
||||
self.Used = self.Total - self.Free
|
||||
self.ActualFree = self.Free + kern
|
||||
self.ActualUsed = self.Used - kern
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type xsw_usage struct {
|
||||
Total, Avail, Used uint64
|
||||
}
|
||||
|
||||
func (self *Swap) Get() error {
|
||||
sw_usage := xsw_usage{}
|
||||
|
||||
if err := sysctlbyname("vm.swapusage", &sw_usage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Total = sw_usage.Total
|
||||
self.Used = sw_usage.Used
|
||||
self.Free = sw_usage.Avail
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Cpu) Get() error {
|
||||
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
|
||||
var cpuload C.host_cpu_load_info_data_t
|
||||
|
||||
status := C.host_statistics(C.host_t(C.mach_host_self()),
|
||||
C.HOST_CPU_LOAD_INFO,
|
||||
C.host_info_t(unsafe.Pointer(&cpuload)),
|
||||
&count)
|
||||
|
||||
if status != C.KERN_SUCCESS {
|
||||
return fmt.Errorf("host_statistics error=%d", status)
|
||||
}
|
||||
|
||||
self.User = uint64(cpuload.cpu_ticks[C.CPU_STATE_USER])
|
||||
self.Sys = uint64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM])
|
||||
self.Idle = uint64(cpuload.cpu_ticks[C.CPU_STATE_IDLE])
|
||||
self.Nice = uint64(cpuload.cpu_ticks[C.CPU_STATE_NICE])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CpuList) Get() error {
|
||||
var count C.mach_msg_type_number_t
|
||||
var cpuload *C.processor_cpu_load_info_data_t
|
||||
var ncpu C.natural_t
|
||||
|
||||
status := C.host_processor_info(C.host_t(C.mach_host_self()),
|
||||
C.PROCESSOR_CPU_LOAD_INFO,
|
||||
&ncpu,
|
||||
(*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
|
||||
&count)
|
||||
|
||||
if status != C.KERN_SUCCESS {
|
||||
return fmt.Errorf("host_processor_info error=%d", status)
|
||||
}
|
||||
|
||||
// jump through some cgo casting hoops and ensure we properly free
|
||||
// the memory that cpuload points to
|
||||
target := C.vm_map_t(C.mach_task_self_)
|
||||
address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
|
||||
defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
|
||||
|
||||
// the body of struct processor_cpu_load_info
|
||||
// aka processor_cpu_load_info_data_t
|
||||
var cpu_ticks [C.CPU_STATE_MAX]uint32
|
||||
|
||||
// copy the cpuload array to a []byte buffer
|
||||
// where we can binary.Read the data
|
||||
size := int(ncpu) * binary.Size(cpu_ticks)
|
||||
buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))
|
||||
|
||||
bbuf := bytes.NewBuffer(buf)
|
||||
|
||||
self.List = make([]Cpu, 0, ncpu)
|
||||
|
||||
for i := 0; i < int(ncpu); i++ {
|
||||
cpu := Cpu{}
|
||||
|
||||
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cpu.User = uint64(cpu_ticks[C.CPU_STATE_USER])
|
||||
cpu.Sys = uint64(cpu_ticks[C.CPU_STATE_SYSTEM])
|
||||
cpu.Idle = uint64(cpu_ticks[C.CPU_STATE_IDLE])
|
||||
cpu.Nice = uint64(cpu_ticks[C.CPU_STATE_NICE])
|
||||
|
||||
self.List = append(self.List, cpu)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FileSystemList) Get() error {
|
||||
num, err := getfsstat(nil, C.MNT_NOWAIT)
|
||||
if num < 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]syscall.Statfs_t, num)
|
||||
|
||||
num, err = getfsstat(buf, C.MNT_NOWAIT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fslist := make([]FileSystem, 0, num)
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
fs := FileSystem{}
|
||||
|
||||
fs.DirName = bytePtrToString(&buf[i].Mntonname[0])
|
||||
fs.DevName = bytePtrToString(&buf[i].Mntfromname[0])
|
||||
fs.SysTypeName = bytePtrToString(&buf[i].Fstypename[0])
|
||||
|
||||
fslist = append(fslist, fs)
|
||||
}
|
||||
|
||||
self.List = fslist
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *ProcList) Get() error {
|
||||
n := C.proc_listpids(C.PROC_ALL_PIDS, 0, nil, 0)
|
||||
if n <= 0 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
n = C.proc_listpids(C.PROC_ALL_PIDS, 0, unsafe.Pointer(&buf[0]), n)
|
||||
if n <= 0 {
|
||||
return syscall.ENOMEM
|
||||
}
|
||||
|
||||
var pid int32
|
||||
num := int(n) / binary.Size(pid)
|
||||
list := make([]int, 0, num)
|
||||
bbuf := bytes.NewBuffer(buf)
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
if err := binary.Read(bbuf, binary.LittleEndian, &pid); err != nil {
|
||||
return err
|
||||
}
|
||||
if pid == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, int(pid))
|
||||
}
|
||||
|
||||
self.List = list
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcState) Get(pid int) error {
|
||||
info := C.struct_proc_taskallinfo{}
|
||||
|
||||
if err := task_info(pid, &info); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Name = C.GoString(&info.pbsd.pbi_comm[0])
|
||||
|
||||
switch info.pbsd.pbi_status {
|
||||
case C.SIDL:
|
||||
self.State = RunStateIdle
|
||||
case C.SRUN:
|
||||
self.State = RunStateRun
|
||||
case C.SSLEEP:
|
||||
self.State = RunStateSleep
|
||||
case C.SSTOP:
|
||||
self.State = RunStateStop
|
||||
case C.SZOMB:
|
||||
self.State = RunStateZombie
|
||||
default:
|
||||
self.State = RunStateUnknown
|
||||
}
|
||||
|
||||
self.Ppid = int(info.pbsd.pbi_ppid)
|
||||
|
||||
self.Tty = int(info.pbsd.e_tdev)
|
||||
|
||||
self.Priority = int(info.ptinfo.pti_priority)
|
||||
|
||||
self.Nice = int(info.pbsd.pbi_nice)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcMem) Get(pid int) error {
|
||||
info := C.struct_proc_taskallinfo{}
|
||||
|
||||
if err := task_info(pid, &info); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Size = uint64(info.ptinfo.pti_virtual_size)
|
||||
self.Resident = uint64(info.ptinfo.pti_resident_size)
|
||||
self.PageFaults = uint64(info.ptinfo.pti_faults)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcTime) Get(pid int) error {
|
||||
info := C.struct_proc_taskallinfo{}
|
||||
|
||||
if err := task_info(pid, &info); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.User =
|
||||
uint64(info.ptinfo.pti_total_user) / uint64(time.Millisecond)
|
||||
|
||||
self.Sys =
|
||||
uint64(info.ptinfo.pti_total_system) / uint64(time.Millisecond)
|
||||
|
||||
self.Total = self.User + self.Sys
|
||||
|
||||
self.StartTime = (uint64(info.pbsd.pbi_start_tvsec) * 1000) +
|
||||
(uint64(info.pbsd.pbi_start_tvusec) / 1000)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcArgs) Get(pid int) error {
|
||||
var args []string
|
||||
|
||||
argv := func(arg string) {
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
err := kern_procargs(pid, nil, argv, nil)
|
||||
|
||||
self.List = args
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *ProcExe) Get(pid int) error {
|
||||
exe := func(arg string) {
|
||||
self.Name = arg
|
||||
}
|
||||
|
||||
return kern_procargs(pid, exe, nil, nil)
|
||||
}
|
||||
|
||||
// wrapper around sysctl KERN_PROCARGS2
|
||||
// callbacks params are optional,
|
||||
// up to the caller as to which pieces of data they want
|
||||
func kern_procargs(pid int,
|
||||
exe func(string),
|
||||
argv func(string),
|
||||
env func(string, string)) error {
|
||||
|
||||
mib := []C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
|
||||
argmax := uintptr(C.ARG_MAX)
|
||||
buf := make([]byte, argmax)
|
||||
err := sysctl(mib, &buf[0], &argmax, nil, 0)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bbuf := bytes.NewBuffer(buf)
|
||||
bbuf.Truncate(int(argmax))
|
||||
|
||||
var argc int32
|
||||
binary.Read(bbuf, binary.LittleEndian, &argc)
|
||||
|
||||
path, err := bbuf.ReadBytes(0)
|
||||
if exe != nil {
|
||||
exe(string(chop(path)))
|
||||
}
|
||||
|
||||
// skip trailing \0's
|
||||
for {
|
||||
c, _ := bbuf.ReadByte()
|
||||
if c != 0 {
|
||||
bbuf.UnreadByte()
|
||||
break // start of argv[0]
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < int(argc); i++ {
|
||||
arg, err := bbuf.ReadBytes(0)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if argv != nil {
|
||||
argv(string(chop(arg)))
|
||||
}
|
||||
}
|
||||
|
||||
if env == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
delim := []byte{61} // "="
|
||||
|
||||
for {
|
||||
line, err := bbuf.ReadBytes(0)
|
||||
if err == io.EOF || line[0] == 0 {
|
||||
break
|
||||
}
|
||||
pair := bytes.SplitN(chop(line), delim, 2)
|
||||
env(string(pair[0]), string(pair[1]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// XXX copied from zsyscall_darwin_amd64.go
|
||||
func sysctl(mib []C.int, old *byte, oldlen *uintptr,
|
||||
new *byte, newlen uintptr) (err error) {
|
||||
var p0 unsafe.Pointer
|
||||
p0 = unsafe.Pointer(&mib[0])
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p0),
|
||||
uintptr(len(mib)),
|
||||
uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)),
|
||||
uintptr(unsafe.Pointer(new)), uintptr(newlen))
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func vm_info(vmstat *C.vm_statistics_data_t) error {
|
||||
var count C.mach_msg_type_number_t = C.HOST_VM_INFO_COUNT
|
||||
|
||||
status := C.host_statistics(
|
||||
C.host_t(C.mach_host_self()),
|
||||
C.HOST_VM_INFO,
|
||||
C.host_info_t(unsafe.Pointer(vmstat)),
|
||||
&count)
|
||||
|
||||
if status != C.KERN_SUCCESS {
|
||||
return fmt.Errorf("host_statistics=%d", status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generic Sysctl buffer unmarshalling
|
||||
func sysctlbyname(name string, data interface{}) (err error) {
|
||||
val, err := syscall.Sysctl(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := []byte(val)
|
||||
|
||||
switch v := data.(type) {
|
||||
case *uint64:
|
||||
*v = *(*uint64)(unsafe.Pointer(&buf[0]))
|
||||
return
|
||||
}
|
||||
|
||||
bbuf := bytes.NewBuffer([]byte(val))
|
||||
return binary.Read(bbuf, binary.LittleEndian, data)
|
||||
}
|
||||
|
||||
// syscall.Getfsstat() wrapper is broken, roll our own to workaround.
|
||||
func getfsstat(buf []syscall.Statfs_t, flags int) (n int, err error) {
|
||||
var ptr uintptr
|
||||
var size uintptr
|
||||
|
||||
if len(buf) > 0 {
|
||||
ptr = uintptr(unsafe.Pointer(&buf[0]))
|
||||
size = unsafe.Sizeof(buf[0]) * uintptr(len(buf))
|
||||
} else {
|
||||
ptr = uintptr(0)
|
||||
size = uintptr(0)
|
||||
}
|
||||
|
||||
trap := uintptr(syscall.SYS_GETFSSTAT64)
|
||||
ret, _, errno := syscall.Syscall(trap, ptr, size, uintptr(flags))
|
||||
|
||||
n = int(ret)
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func task_info(pid int, info *C.struct_proc_taskallinfo) error {
|
||||
size := C.int(unsafe.Sizeof(*info))
|
||||
ptr := unsafe.Pointer(info)
|
||||
|
||||
n := C.proc_pidinfo(C.int(pid), C.PROC_PIDTASKALLINFO, 0, ptr, size)
|
||||
if n != size {
|
||||
return syscall.ENOMEM
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
126
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_format.go
generated
vendored
Normal file
126
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_format.go
generated
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package sigar
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Go version of apr_strfsize
|
||||
func FormatSize(size uint64) string {
|
||||
ord := []string{"K", "M", "G", "T", "P", "E"}
|
||||
o := 0
|
||||
buf := new(bytes.Buffer)
|
||||
w := bufio.NewWriter(buf)
|
||||
|
||||
if size < 973 {
|
||||
fmt.Fprintf(w, "%3d ", size)
|
||||
w.Flush()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
for {
|
||||
remain := size & 1023
|
||||
size >>= 10
|
||||
|
||||
if size >= 973 {
|
||||
o++
|
||||
continue
|
||||
}
|
||||
|
||||
if size < 9 || (size == 9 && remain < 973) {
|
||||
remain = ((remain * 5) + 256) / 512
|
||||
if remain >= 10 {
|
||||
size++
|
||||
remain = 0
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%d.%d%s", size, remain, ord[o])
|
||||
break
|
||||
}
|
||||
|
||||
if remain >= 512 {
|
||||
size++
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%3d%s", size, ord[o])
|
||||
break
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func FormatPercent(percent float64) string {
|
||||
return strconv.FormatFloat(percent, 'f', -1, 64) + "%"
|
||||
}
|
||||
|
||||
func (self *FileSystemUsage) UsePercent() float64 {
|
||||
b_used := (self.Total - self.Free) / 1024
|
||||
b_avail := self.Avail / 1024
|
||||
utotal := b_used + b_avail
|
||||
used := b_used
|
||||
|
||||
if utotal != 0 {
|
||||
u100 := used * 100
|
||||
pct := u100 / utotal
|
||||
if u100%utotal != 0 {
|
||||
pct += 1
|
||||
}
|
||||
return (float64(pct) / float64(100)) * 100.0
|
||||
}
|
||||
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func (self *Uptime) Format() string {
|
||||
buf := new(bytes.Buffer)
|
||||
w := bufio.NewWriter(buf)
|
||||
uptime := uint64(self.Length)
|
||||
|
||||
days := uptime / (60 * 60 * 24)
|
||||
|
||||
if days != 0 {
|
||||
s := ""
|
||||
if days > 1 {
|
||||
s = "s"
|
||||
}
|
||||
fmt.Fprintf(w, "%d day%s, ", days, s)
|
||||
}
|
||||
|
||||
minutes := uptime / 60
|
||||
hours := minutes / 60
|
||||
hours %= 24
|
||||
minutes %= 60
|
||||
|
||||
fmt.Fprintf(w, "%2d:%02d", hours, minutes)
|
||||
|
||||
w.Flush()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (self *ProcTime) FormatStartTime() string {
|
||||
if self.StartTime == 0 {
|
||||
return "00:00"
|
||||
}
|
||||
start := time.Unix(int64(self.StartTime)/1000, 0)
|
||||
format := "Jan02"
|
||||
if time.Since(start).Seconds() < (60 * 60 * 24) {
|
||||
format = "15:04"
|
||||
}
|
||||
return start.Format(format)
|
||||
}
|
||||
|
||||
func (self *ProcTime) FormatTotal() string {
|
||||
t := self.Total / 1000
|
||||
ss := t % 60
|
||||
t /= 60
|
||||
mm := t % 60
|
||||
t /= 60
|
||||
hh := t % 24
|
||||
return fmt.Sprintf("%02d:%02d:%02d", hh, mm, ss)
|
||||
}
|
141
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_interface.go
generated
vendored
Normal file
141
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_interface.go
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
package sigar
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Sigar interface {
|
||||
CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{})
|
||||
GetLoadAverage() (LoadAverage, error)
|
||||
GetMem() (Mem, error)
|
||||
GetSwap() (Swap, error)
|
||||
GetFileSystemUsage(string) (FileSystemUsage, error)
|
||||
}
|
||||
|
||||
type Cpu struct {
|
||||
User uint64
|
||||
Nice uint64
|
||||
Sys uint64
|
||||
Idle uint64
|
||||
Wait uint64
|
||||
Irq uint64
|
||||
SoftIrq uint64
|
||||
Stolen uint64
|
||||
}
|
||||
|
||||
func (cpu *Cpu) Total() uint64 {
|
||||
return cpu.User + cpu.Nice + cpu.Sys + cpu.Idle +
|
||||
cpu.Wait + cpu.Irq + cpu.SoftIrq + cpu.Stolen
|
||||
}
|
||||
|
||||
func (cpu Cpu) Delta(other Cpu) Cpu {
|
||||
return Cpu{
|
||||
User: cpu.User - other.User,
|
||||
Nice: cpu.Nice - other.Nice,
|
||||
Sys: cpu.Sys - other.Sys,
|
||||
Idle: cpu.Idle - other.Idle,
|
||||
Wait: cpu.Wait - other.Wait,
|
||||
Irq: cpu.Irq - other.Irq,
|
||||
SoftIrq: cpu.SoftIrq - other.SoftIrq,
|
||||
Stolen: cpu.Stolen - other.Stolen,
|
||||
}
|
||||
}
|
||||
|
||||
type LoadAverage struct {
|
||||
One, Five, Fifteen float64
|
||||
}
|
||||
|
||||
type Uptime struct {
|
||||
Length float64
|
||||
}
|
||||
|
||||
type Mem struct {
|
||||
Total uint64
|
||||
Used uint64
|
||||
Free uint64
|
||||
ActualFree uint64
|
||||
ActualUsed uint64
|
||||
}
|
||||
|
||||
type Swap struct {
|
||||
Total uint64
|
||||
Used uint64
|
||||
Free uint64
|
||||
}
|
||||
|
||||
type CpuList struct {
|
||||
List []Cpu
|
||||
}
|
||||
|
||||
type FileSystem struct {
|
||||
DirName string
|
||||
DevName string
|
||||
TypeName string
|
||||
SysTypeName string
|
||||
Options string
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type FileSystemList struct {
|
||||
List []FileSystem
|
||||
}
|
||||
|
||||
type FileSystemUsage struct {
|
||||
Total uint64
|
||||
Used uint64
|
||||
Free uint64
|
||||
Avail uint64
|
||||
Files uint64
|
||||
FreeFiles uint64
|
||||
}
|
||||
|
||||
type ProcList struct {
|
||||
List []int
|
||||
}
|
||||
|
||||
type RunState byte
|
||||
|
||||
const (
|
||||
RunStateSleep = 'S'
|
||||
RunStateRun = 'R'
|
||||
RunStateStop = 'T'
|
||||
RunStateZombie = 'Z'
|
||||
RunStateIdle = 'D'
|
||||
RunStateUnknown = '?'
|
||||
)
|
||||
|
||||
type ProcState struct {
|
||||
Name string
|
||||
State RunState
|
||||
Ppid int
|
||||
Tty int
|
||||
Priority int
|
||||
Nice int
|
||||
Processor int
|
||||
}
|
||||
|
||||
type ProcMem struct {
|
||||
Size uint64
|
||||
Resident uint64
|
||||
Share uint64
|
||||
MinorFaults uint64
|
||||
MajorFaults uint64
|
||||
PageFaults uint64
|
||||
}
|
||||
|
||||
type ProcTime struct {
|
||||
StartTime uint64
|
||||
User uint64
|
||||
Sys uint64
|
||||
Total uint64
|
||||
}
|
||||
|
||||
type ProcArgs struct {
|
||||
List []string
|
||||
}
|
||||
|
||||
type ProcExe struct {
|
||||
Name string
|
||||
Cwd string
|
||||
Root string
|
||||
}
|
135
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_interface_test.go
generated
vendored
Normal file
135
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_interface_test.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
package sigar_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
. "github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
var _ = Describe("Sigar", func() {
|
||||
var invalidPid = 666666
|
||||
|
||||
It("cpu", func() {
|
||||
cpu := Cpu{}
|
||||
err := cpu.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("load average", func() {
|
||||
avg := LoadAverage{}
|
||||
err := avg.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("uptime", func() {
|
||||
uptime := Uptime{}
|
||||
err := uptime.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(uptime.Length).To(BeNumerically(">", 0))
|
||||
})
|
||||
|
||||
It("mem", func() {
|
||||
mem := Mem{}
|
||||
err := mem.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(mem.Total).To(BeNumerically(">", 0))
|
||||
Expect(mem.Used + mem.Free).To(BeNumerically("<=", mem.Total))
|
||||
})
|
||||
|
||||
It("swap", func() {
|
||||
swap := Swap{}
|
||||
err := swap.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(swap.Used + swap.Free).To(BeNumerically("<=", swap.Total))
|
||||
})
|
||||
|
||||
It("cpu list", func() {
|
||||
cpulist := CpuList{}
|
||||
err := cpulist.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
nsigar := len(cpulist.List)
|
||||
numcpu := runtime.NumCPU()
|
||||
Expect(nsigar).To(Equal(numcpu))
|
||||
})
|
||||
|
||||
It("file system list", func() {
|
||||
fslist := FileSystemList{}
|
||||
err := fslist.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(fslist.List)).To(BeNumerically(">", 0))
|
||||
})
|
||||
|
||||
It("file system usage", func() {
|
||||
fsusage := FileSystemUsage{}
|
||||
err := fsusage.Get("/")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = fsusage.Get("T O T A L L Y B O G U S")
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("proc list", func() {
|
||||
pids := ProcList{}
|
||||
err := pids.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(pids.List)).To(BeNumerically(">", 2))
|
||||
|
||||
err = pids.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("proc state", func() {
|
||||
state := ProcState{}
|
||||
err := state.Get(os.Getppid())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect([]RunState{RunStateRun, RunStateSleep}).To(ContainElement(state.State))
|
||||
Expect([]string{"go", "ginkgo"}).To(ContainElement(state.Name))
|
||||
|
||||
err = state.Get(invalidPid)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("proc mem", func() {
|
||||
mem := ProcMem{}
|
||||
err := mem.Get(os.Getppid())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = mem.Get(invalidPid)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("proc time", func() {
|
||||
time := ProcTime{}
|
||||
err := time.Get(os.Getppid())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = time.Get(invalidPid)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("proc args", func() {
|
||||
args := ProcArgs{}
|
||||
err := args.Get(os.Getppid())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(args.List)).To(BeNumerically(">=", 2))
|
||||
})
|
||||
|
||||
It("proc exe", func() {
|
||||
exe := ProcExe{}
|
||||
err := exe.Get(os.Getppid())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect([]string{"go", "ginkgo"}).To(ContainElement(filepath.Base(exe.Name)))
|
||||
})
|
||||
})
|
386
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_linux.go
generated
vendored
Normal file
386
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,386 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package sigar
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var system struct {
|
||||
ticks uint64
|
||||
btime uint64
|
||||
}
|
||||
|
||||
var Procd string
|
||||
|
||||
func init() {
|
||||
system.ticks = 100 // C.sysconf(C._SC_CLK_TCK)
|
||||
|
||||
Procd = "/proc"
|
||||
|
||||
// grab system boot time
|
||||
readFile(Procd+"/stat", func(line string) bool {
|
||||
if strings.HasPrefix(line, "btime") {
|
||||
system.btime, _ = strtoull(line[6:])
|
||||
return false // stop reading
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LoadAverage) Get() error {
|
||||
line, err := ioutil.ReadFile(Procd + "/loadavg")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fields := strings.Fields(string(line))
|
||||
|
||||
self.One, _ = strconv.ParseFloat(fields[0], 64)
|
||||
self.Five, _ = strconv.ParseFloat(fields[1], 64)
|
||||
self.Fifteen, _ = strconv.ParseFloat(fields[2], 64)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Uptime) Get() error {
|
||||
sysinfo := syscall.Sysinfo_t{}
|
||||
|
||||
if err := syscall.Sysinfo(&sysinfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Length = float64(sysinfo.Uptime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Mem) Get() error {
|
||||
var buffers, cached uint64
|
||||
table := map[string]*uint64{
|
||||
"MemTotal": &self.Total,
|
||||
"MemFree": &self.Free,
|
||||
"Buffers": &buffers,
|
||||
"Cached": &cached,
|
||||
}
|
||||
|
||||
if err := parseMeminfo(table); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Used = self.Total - self.Free
|
||||
kern := buffers + cached
|
||||
self.ActualFree = self.Free + kern
|
||||
self.ActualUsed = self.Used - kern
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Swap) Get() error {
|
||||
table := map[string]*uint64{
|
||||
"SwapTotal": &self.Total,
|
||||
"SwapFree": &self.Free,
|
||||
}
|
||||
|
||||
if err := parseMeminfo(table); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Used = self.Total - self.Free
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Cpu) Get() error {
|
||||
return readFile(Procd+"/stat", func(line string) bool {
|
||||
if len(line) > 4 && line[0:4] == "cpu " {
|
||||
parseCpuStat(self, line)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func (self *CpuList) Get() error {
|
||||
capacity := len(self.List)
|
||||
if capacity == 0 {
|
||||
capacity = 4
|
||||
}
|
||||
list := make([]Cpu, 0, capacity)
|
||||
|
||||
err := readFile(Procd+"/stat", func(line string) bool {
|
||||
if len(line) > 3 && line[0:3] == "cpu" && line[3] != ' ' {
|
||||
cpu := Cpu{}
|
||||
parseCpuStat(&cpu, line)
|
||||
list = append(list, cpu)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
self.List = list
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *FileSystemList) Get() error {
|
||||
capacity := len(self.List)
|
||||
if capacity == 0 {
|
||||
capacity = 10
|
||||
}
|
||||
fslist := make([]FileSystem, 0, capacity)
|
||||
|
||||
err := readFile("/etc/mtab", func(line string) bool {
|
||||
fields := strings.Fields(line)
|
||||
|
||||
fs := FileSystem{}
|
||||
fs.DevName = fields[0]
|
||||
fs.DirName = fields[1]
|
||||
fs.SysTypeName = fields[2]
|
||||
fs.Options = fields[3]
|
||||
|
||||
fslist = append(fslist, fs)
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
self.List = fslist
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *ProcList) Get() error {
|
||||
dir, err := os.Open(Procd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
const readAllDirnames = -1 // see os.File.Readdirnames doc
|
||||
|
||||
names, err := dir.Readdirnames(readAllDirnames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
capacity := len(names)
|
||||
list := make([]int, 0, capacity)
|
||||
|
||||
for _, name := range names {
|
||||
if name[0] < '0' || name[0] > '9' {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(name)
|
||||
if err == nil {
|
||||
list = append(list, pid)
|
||||
}
|
||||
}
|
||||
|
||||
self.List = list
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcState) Get(pid int) error {
|
||||
contents, err := readProcFile(pid, "stat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := strings.Fields(string(contents))
|
||||
|
||||
self.Name = fields[1][1 : len(fields[1])-1] // strip ()'s
|
||||
|
||||
self.State = RunState(fields[2][0])
|
||||
|
||||
self.Ppid, _ = strconv.Atoi(fields[3])
|
||||
|
||||
self.Tty, _ = strconv.Atoi(fields[6])
|
||||
|
||||
self.Priority, _ = strconv.Atoi(fields[17])
|
||||
|
||||
self.Nice, _ = strconv.Atoi(fields[18])
|
||||
|
||||
self.Processor, _ = strconv.Atoi(fields[38])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcMem) Get(pid int) error {
|
||||
contents, err := readProcFile(pid, "statm")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := strings.Fields(string(contents))
|
||||
|
||||
size, _ := strtoull(fields[0])
|
||||
self.Size = size << 12
|
||||
|
||||
rss, _ := strtoull(fields[1])
|
||||
self.Resident = rss << 12
|
||||
|
||||
share, _ := strtoull(fields[2])
|
||||
self.Share = share << 12
|
||||
|
||||
contents, err = readProcFile(pid, "stat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields = strings.Fields(string(contents))
|
||||
|
||||
self.MinorFaults, _ = strtoull(fields[10])
|
||||
self.MajorFaults, _ = strtoull(fields[12])
|
||||
self.PageFaults = self.MinorFaults + self.MajorFaults
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcTime) Get(pid int) error {
|
||||
contents, err := readProcFile(pid, "stat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := strings.Fields(string(contents))
|
||||
|
||||
user, _ := strtoull(fields[13])
|
||||
sys, _ := strtoull(fields[14])
|
||||
// convert to millis
|
||||
self.User = user * (1000 / system.ticks)
|
||||
self.Sys = sys * (1000 / system.ticks)
|
||||
self.Total = self.User + self.Sys
|
||||
|
||||
// convert to millis
|
||||
self.StartTime, _ = strtoull(fields[21])
|
||||
self.StartTime /= system.ticks
|
||||
self.StartTime += system.btime
|
||||
self.StartTime *= 1000
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcArgs) Get(pid int) error {
|
||||
contents, err := readProcFile(pid, "cmdline")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bbuf := bytes.NewBuffer(contents)
|
||||
|
||||
var args []string
|
||||
|
||||
for {
|
||||
arg, err := bbuf.ReadBytes(0)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
args = append(args, string(chop(arg)))
|
||||
}
|
||||
|
||||
self.List = args
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ProcExe) Get(pid int) error {
|
||||
fields := map[string]*string{
|
||||
"exe": &self.Name,
|
||||
"cwd": &self.Cwd,
|
||||
"root": &self.Root,
|
||||
}
|
||||
|
||||
for name, field := range fields {
|
||||
val, err := os.Readlink(procFileName(pid, name))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*field = val
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMeminfo(table map[string]*uint64) error {
|
||||
return readFile(Procd+"/meminfo", func(line string) bool {
|
||||
fields := strings.Split(line, ":")
|
||||
|
||||
if ptr := table[fields[0]]; ptr != nil {
|
||||
num := strings.TrimLeft(fields[1], " ")
|
||||
val, err := strtoull(strings.Fields(num)[0])
|
||||
if err == nil {
|
||||
*ptr = val * 1024
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func parseCpuStat(self *Cpu, line string) error {
|
||||
fields := strings.Fields(line)
|
||||
|
||||
self.User, _ = strtoull(fields[1])
|
||||
self.Nice, _ = strtoull(fields[2])
|
||||
self.Sys, _ = strtoull(fields[3])
|
||||
self.Idle, _ = strtoull(fields[4])
|
||||
self.Wait, _ = strtoull(fields[5])
|
||||
self.Irq, _ = strtoull(fields[6])
|
||||
self.SoftIrq, _ = strtoull(fields[7])
|
||||
self.Stolen, _ = strtoull(fields[8])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFile(file string, handler func(string) bool) error {
|
||||
contents, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(bytes.NewBuffer(contents))
|
||||
|
||||
for {
|
||||
line, _, err := reader.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if !handler(string(line)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func strtoull(val string) (uint64, error) {
|
||||
return strconv.ParseUint(val, 10, 64)
|
||||
}
|
||||
|
||||
func procFileName(pid int, name string) string {
|
||||
return Procd + "/" + strconv.Itoa(pid) + "/" + name
|
||||
}
|
||||
|
||||
func readProcFile(pid int, name string) ([]byte, error) {
|
||||
path := procFileName(pid, name)
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
if perr, ok := err.(*os.PathError); ok {
|
||||
if perr.Err == syscall.ENOENT {
|
||||
return nil, syscall.ESRCH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return contents, err
|
||||
}
|
225
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_linux_test.go
generated
vendored
Normal file
225
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
package sigar_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
sigar "github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
var _ = Describe("sigarLinux", func() {
|
||||
var procd string
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
procd, err = ioutil.TempDir("", "sigarTests")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
sigar.Procd = procd
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
sigar.Procd = "/proc"
|
||||
})
|
||||
|
||||
Describe("CPU", func() {
|
||||
var (
|
||||
statFile string
|
||||
cpu sigar.Cpu
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
statFile = procd + "/stat"
|
||||
cpu = sigar.Cpu{}
|
||||
})
|
||||
|
||||
Describe("Get", func() {
|
||||
It("gets CPU usage", func() {
|
||||
statContents := []byte("cpu 25 1 2 3 4 5 6 7")
|
||||
err := ioutil.WriteFile(statFile, statContents, 0644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = cpu.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cpu.User).To(Equal(uint64(25)))
|
||||
})
|
||||
|
||||
It("ignores empty lines", func() {
|
||||
statContents := []byte("cpu ")
|
||||
err := ioutil.WriteFile(statFile, statContents, 0644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = cpu.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cpu.User).To(Equal(uint64(0)))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("CollectCpuStats", func() {
|
||||
It("collects CPU usage over time", func() {
|
||||
statContents := []byte("cpu 25 1 2 3 4 5 6 7")
|
||||
err := ioutil.WriteFile(statFile, statContents, 0644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
concreteSigar := &sigar.ConcreteSigar{}
|
||||
cpuUsages, stop := concreteSigar.CollectCpuStats(500 * time.Millisecond)
|
||||
|
||||
Expect(<-cpuUsages).To(Equal(sigar.Cpu{
|
||||
User: uint64(25),
|
||||
Nice: uint64(1),
|
||||
Sys: uint64(2),
|
||||
Idle: uint64(3),
|
||||
Wait: uint64(4),
|
||||
Irq: uint64(5),
|
||||
SoftIrq: uint64(6),
|
||||
Stolen: uint64(7),
|
||||
}))
|
||||
|
||||
statContents = []byte("cpu 30 3 7 10 25 55 36 65")
|
||||
err = ioutil.WriteFile(statFile, statContents, 0644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(<-cpuUsages).To(Equal(sigar.Cpu{
|
||||
User: uint64(5),
|
||||
Nice: uint64(2),
|
||||
Sys: uint64(5),
|
||||
Idle: uint64(7),
|
||||
Wait: uint64(21),
|
||||
Irq: uint64(50),
|
||||
SoftIrq: uint64(30),
|
||||
Stolen: uint64(58),
|
||||
}))
|
||||
|
||||
stop <- struct{}{}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Mem", func() {
|
||||
var meminfoFile string
|
||||
BeforeEach(func() {
|
||||
meminfoFile = procd + "/meminfo"
|
||||
|
||||
meminfoContents := `
|
||||
MemTotal: 374256 kB
|
||||
MemFree: 274460 kB
|
||||
Buffers: 9764 kB
|
||||
Cached: 38648 kB
|
||||
SwapCached: 0 kB
|
||||
Active: 33772 kB
|
||||
Inactive: 31184 kB
|
||||
Active(anon): 16572 kB
|
||||
Inactive(anon): 552 kB
|
||||
Active(file): 17200 kB
|
||||
Inactive(file): 30632 kB
|
||||
Unevictable: 0 kB
|
||||
Mlocked: 0 kB
|
||||
SwapTotal: 786428 kB
|
||||
SwapFree: 786428 kB
|
||||
Dirty: 0 kB
|
||||
Writeback: 0 kB
|
||||
AnonPages: 16564 kB
|
||||
Mapped: 6612 kB
|
||||
Shmem: 584 kB
|
||||
Slab: 19092 kB
|
||||
SReclaimable: 9128 kB
|
||||
SUnreclaim: 9964 kB
|
||||
KernelStack: 672 kB
|
||||
PageTables: 1864 kB
|
||||
NFS_Unstable: 0 kB
|
||||
Bounce: 0 kB
|
||||
WritebackTmp: 0 kB
|
||||
CommitLimit: 973556 kB
|
||||
Committed_AS: 55880 kB
|
||||
VmallocTotal: 34359738367 kB
|
||||
VmallocUsed: 21428 kB
|
||||
VmallocChunk: 34359713596 kB
|
||||
HardwareCorrupted: 0 kB
|
||||
AnonHugePages: 0 kB
|
||||
HugePages_Total: 0
|
||||
HugePages_Free: 0
|
||||
HugePages_Rsvd: 0
|
||||
HugePages_Surp: 0
|
||||
Hugepagesize: 2048 kB
|
||||
DirectMap4k: 59328 kB
|
||||
DirectMap2M: 333824 kB
|
||||
`
|
||||
err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("returns correct memory info", func() {
|
||||
mem := sigar.Mem{}
|
||||
err := mem.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(mem.Total).To(BeNumerically("==", 374256*1024))
|
||||
Expect(mem.Free).To(BeNumerically("==", 274460*1024))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Swap", func() {
|
||||
var meminfoFile string
|
||||
BeforeEach(func() {
|
||||
meminfoFile = procd + "/meminfo"
|
||||
|
||||
meminfoContents := `
|
||||
MemTotal: 374256 kB
|
||||
MemFree: 274460 kB
|
||||
Buffers: 9764 kB
|
||||
Cached: 38648 kB
|
||||
SwapCached: 0 kB
|
||||
Active: 33772 kB
|
||||
Inactive: 31184 kB
|
||||
Active(anon): 16572 kB
|
||||
Inactive(anon): 552 kB
|
||||
Active(file): 17200 kB
|
||||
Inactive(file): 30632 kB
|
||||
Unevictable: 0 kB
|
||||
Mlocked: 0 kB
|
||||
SwapTotal: 786428 kB
|
||||
SwapFree: 786428 kB
|
||||
Dirty: 0 kB
|
||||
Writeback: 0 kB
|
||||
AnonPages: 16564 kB
|
||||
Mapped: 6612 kB
|
||||
Shmem: 584 kB
|
||||
Slab: 19092 kB
|
||||
SReclaimable: 9128 kB
|
||||
SUnreclaim: 9964 kB
|
||||
KernelStack: 672 kB
|
||||
PageTables: 1864 kB
|
||||
NFS_Unstable: 0 kB
|
||||
Bounce: 0 kB
|
||||
WritebackTmp: 0 kB
|
||||
CommitLimit: 973556 kB
|
||||
Committed_AS: 55880 kB
|
||||
VmallocTotal: 34359738367 kB
|
||||
VmallocUsed: 21428 kB
|
||||
VmallocChunk: 34359713596 kB
|
||||
HardwareCorrupted: 0 kB
|
||||
AnonHugePages: 0 kB
|
||||
HugePages_Total: 0
|
||||
HugePages_Free: 0
|
||||
HugePages_Rsvd: 0
|
||||
HugePages_Surp: 0
|
||||
Hugepagesize: 2048 kB
|
||||
DirectMap4k: 59328 kB
|
||||
DirectMap2M: 333824 kB
|
||||
`
|
||||
err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("returns correct memory info", func() {
|
||||
swap := sigar.Swap{}
|
||||
err := swap.Get()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(swap.Total).To(BeNumerically("==", 786428*1024))
|
||||
Expect(swap.Free).To(BeNumerically("==", 786428*1024))
|
||||
})
|
||||
})
|
||||
})
|
13
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_suite_test.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_suite_test.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
package sigar_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGosigar(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Gosigar Suite")
|
||||
}
|
26
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_unix.go
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
// +build darwin freebsd linux netbsd openbsd
|
||||
|
||||
package sigar
|
||||
|
||||
import "syscall"
|
||||
|
||||
func (self *FileSystemUsage) Get(path string) error {
|
||||
stat := syscall.Statfs_t{}
|
||||
err := syscall.Statfs(path, &stat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bsize := stat.Bsize / 512
|
||||
|
||||
self.Total = (uint64(stat.Blocks) * uint64(bsize)) >> 1
|
||||
self.Free = (uint64(stat.Bfree) * uint64(bsize)) >> 1
|
||||
self.Avail = (uint64(stat.Bavail) * uint64(bsize)) >> 1
|
||||
self.Used = self.Total - self.Free
|
||||
self.Files = stat.Files
|
||||
self.FreeFiles = stat.Ffree
|
||||
|
||||
return nil
|
||||
}
|
22
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_util.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_util.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package sigar
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func bytePtrToString(ptr *int8) string {
|
||||
bytes := (*[10000]byte)(unsafe.Pointer(ptr))
|
||||
|
||||
n := 0
|
||||
for bytes[n] != 0 {
|
||||
n++
|
||||
}
|
||||
|
||||
return string(bytes[0:n])
|
||||
}
|
||||
|
||||
func chop(buf []byte) []byte {
|
||||
return buf[0 : len(buf)-1]
|
||||
}
|
100
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_windows.go
generated
vendored
Normal file
100
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) 2012 VMware, Inc.
|
||||
|
||||
package sigar
|
||||
|
||||
// #include <stdlib.h>
|
||||
// #include <windows.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func (self *LoadAverage) Get() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Uptime) Get() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Mem) Get() error {
|
||||
var statex C.MEMORYSTATUSEX
|
||||
statex.dwLength = C.DWORD(unsafe.Sizeof(statex))
|
||||
|
||||
succeeded := C.GlobalMemoryStatusEx(&statex)
|
||||
if succeeded == C.FALSE {
|
||||
lastError := C.GetLastError()
|
||||
return fmt.Errorf("GlobalMemoryStatusEx failed with error: %d", int(lastError))
|
||||
}
|
||||
|
||||
self.Total = uint64(statex.ullTotalPhys)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Swap) Get() error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *Cpu) Get() error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *CpuList) Get() error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *FileSystemList) Get() error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcList) Get() error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcState) Get(pid int) error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcMem) Get(pid int) error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcTime) Get(pid int) error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcArgs) Get(pid int) error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *ProcExe) Get(pid int) error {
|
||||
return notImplemented()
|
||||
}
|
||||
|
||||
func (self *FileSystemUsage) Get(path string) error {
|
||||
var availableBytes C.ULARGE_INTEGER
|
||||
var totalBytes C.ULARGE_INTEGER
|
||||
var totalFreeBytes C.ULARGE_INTEGER
|
||||
|
||||
pathChars := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(pathChars))
|
||||
|
||||
succeeded := C.GetDiskFreeSpaceEx((*C.CHAR)(pathChars), &availableBytes, &totalBytes, &totalFreeBytes)
|
||||
if succeeded == C.FALSE {
|
||||
lastError := C.GetLastError()
|
||||
return fmt.Errorf("GetDiskFreeSpaceEx failed with error: %d", int(lastError))
|
||||
}
|
||||
|
||||
self.Total = *(*uint64)(unsafe.Pointer(&totalBytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
func notImplemented() error {
|
||||
panic("Not Implemented")
|
||||
return nil
|
||||
}
|
32
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_windows_test.go
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/cloudfoundry/gosigar/sigar_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
package sigar_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
sigar "github.com/cloudfoundry/gosigar"
|
||||
)
|
||||
|
||||
var _ = Describe("SigarWindows", func() {
|
||||
Describe("Memory", func() {
|
||||
It("gets the total memory", func() {
|
||||
mem := sigar.Mem{}
|
||||
err := mem.Get()
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(mem.Total).Should(BeNumerically(">", 0))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Disk", func() {
|
||||
It("gets the total disk space", func() {
|
||||
usage := sigar.FileSystemUsage{}
|
||||
err := usage.Get(os.TempDir())
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(usage.Total).Should(BeNumerically(">", 0))
|
||||
})
|
||||
})
|
||||
})
|
2
Makefile
2
Makefile
|
@ -21,7 +21,7 @@ test: prepare docker-compose
|
|||
$(GOPATH)/bin/godep go test -v ./...
|
||||
|
||||
test-short: prepare
|
||||
$(GOPATH)/bin/godep go test -v -short ./...
|
||||
$(GOPATH)/bin/godep go test -short ./...
|
||||
|
||||
test-cleanup:
|
||||
docker-compose kill
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/influxdb/telegraf/plugins/system/ps/cpu"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/disk"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/docker"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/load"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/mem"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/net"
|
||||
)
|
||||
|
@ -24,7 +23,6 @@ type DockerContainerStat struct {
|
|||
}
|
||||
|
||||
type PS interface {
|
||||
LoadAvg() (*load.LoadAvgStat, error)
|
||||
CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error)
|
||||
DiskUsage() ([]*disk.DiskUsageStat, error)
|
||||
NetIO() ([]net.NetIOCountersStat, error)
|
||||
|
@ -45,10 +43,6 @@ type systemPS struct {
|
|||
dockerClient *dc.Client
|
||||
}
|
||||
|
||||
func (s *systemPS) LoadAvg() (*load.LoadAvgStat, error) {
|
||||
return load.LoadAvg()
|
||||
}
|
||||
|
||||
func (s *systemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error) {
|
||||
var cpuTimes []cpu.CPUTimesStat
|
||||
if perCPU {
|
||||
|
|
|
@ -1,39 +1,48 @@
|
|||
package system
|
||||
|
||||
import "github.com/influxdb/telegraf/plugins"
|
||||
import (
|
||||
"github.com/cloudfoundry/gosigar"
|
||||
|
||||
type SystemStats struct {
|
||||
ps PS
|
||||
}
|
||||
"github.com/influxdb/telegraf/plugins"
|
||||
)
|
||||
|
||||
type SystemStats struct{}
|
||||
|
||||
func (_ *SystemStats) Description() string {
|
||||
return "Read metrics about system load"
|
||||
return "Read metrics about system load & uptime"
|
||||
}
|
||||
|
||||
func (_ *SystemStats) SampleConfig() string { return "" }
|
||||
|
||||
func (s *SystemStats) add(acc plugins.Accumulator,
|
||||
func (_ *SystemStats) add(acc plugins.Accumulator,
|
||||
name string, val float64, tags map[string]string) {
|
||||
if val >= 0 {
|
||||
acc.Add(name, val, tags)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SystemStats) Gather(acc plugins.Accumulator) error {
|
||||
lv, err := s.ps.LoadAvg()
|
||||
if err != nil {
|
||||
func (_ *SystemStats) Gather(acc plugins.Accumulator) error {
|
||||
loadavg := sigar.LoadAverage{}
|
||||
if err := loadavg.Get(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
acc.Add("load1", lv.Load1, nil)
|
||||
acc.Add("load5", lv.Load5, nil)
|
||||
acc.Add("load15", lv.Load15, nil)
|
||||
uptime := sigar.Uptime{}
|
||||
if err := uptime.Get(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
acc.Add("load1", loadavg.One, nil)
|
||||
acc.Add("load5", loadavg.Five, nil)
|
||||
acc.Add("load15", loadavg.Fifteen, nil)
|
||||
acc.Add("uptime", uptime.Length, nil)
|
||||
acc.Add("uptime_format", uptime.Format(), nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugins.Add("system", func() plugins.Plugin {
|
||||
return &SystemStats{ps: &systemPS{}}
|
||||
return &SystemStats{}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/cpu"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/disk"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/load"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/mem"
|
||||
"github.com/influxdb/telegraf/plugins/system/ps/net"
|
||||
"github.com/influxdb/telegraf/testutil"
|
||||
|
@ -22,14 +21,6 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
|||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
lv := &load.LoadAvgStat{
|
||||
Load1: 0.3,
|
||||
Load5: 1.5,
|
||||
Load15: 0.8,
|
||||
}
|
||||
|
||||
mps.On("LoadAvg").Return(lv, nil)
|
||||
|
||||
cts := cpu.CPUTimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 3.1,
|
||||
|
@ -128,15 +119,6 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
|||
|
||||
mps.On("SwapStat").Return(sms, nil)
|
||||
|
||||
ss := &SystemStats{ps: &mps}
|
||||
|
||||
err := ss.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, acc.CheckValue("load1", 0.3))
|
||||
assert.True(t, acc.CheckValue("load5", 1.5))
|
||||
assert.True(t, acc.CheckValue("load15", 0.8))
|
||||
|
||||
cs := NewCPUStats(&mps)
|
||||
|
||||
cputags := map[string]string{
|
||||
|
@ -144,7 +126,7 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
|||
}
|
||||
|
||||
preCPUPoints := len(acc.Points)
|
||||
err = cs.Gather(&acc)
|
||||
err := cs.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
numCPUPoints := len(acc.Points) - preCPUPoints
|
||||
|
||||
|
|
Loading…
Reference in New Issue