Compare commits

..

1 Commits

Author SHA1 Message Date
Cameron Sparr
37ae3956c1 Space Igloo 2016-05-04 11:16:18 -06:00
16 changed files with 497 additions and 157 deletions

View File

@@ -1,4 +1,4 @@
## v0.13 [2016-05-11] ## v0.13 [unreleased]
### Release Notes ### Release Notes
@@ -48,15 +48,7 @@ based on _prefix_ in addition to globs. This means that a filter like
- disque: `host -> disque_host` - disque: `host -> disque_host`
- rethinkdb: `host -> rethinkdb_host` - rethinkdb: `host -> rethinkdb_host`
- **Breaking Change**: The `win_perf_counters` input has been changed to - **Breaking Change**: The `win_perf_counters` input has been changed to sanitize field names, replacing `/Sec` and `/sec` with `_persec`, as well as spaces with underscores. This is needed because Graphite doesn't like slashes and spaces, and was failing to accept metrics that had them. The `/[sS]ec` -> `_persec` is just to make things clearer and uniform.
sanitize field names, replacing `/Sec` and `/sec` with `_persec`, as well as
spaces with underscores. This is needed because Graphite doesn't like slashes
and spaces, and was failing to accept metrics that had them.
The `/[sS]ec` -> `_persec` is just to make things clearer and uniform.
- **Breaking Change**: snmp plugin. The `host` tag of the snmp plugin has been
changed to the `snmp_host` tag.
- The `disk` input plugin can now be configured with the `HOST_MOUNT_PREFIX` environment variable. - The `disk` input plugin can now be configured with the `HOST_MOUNT_PREFIX` environment variable.
This value is prepended to any mountpaths discovered before retrieving stats. This value is prepended to any mountpaths discovered before retrieving stats.
It is not included on the report path. This is necessary for reporting host disk stats when running from within a container. It is not included on the report path. This is necessary for reporting host disk stats when running from within a container.

4
Godeps
View File

@@ -25,7 +25,7 @@ github.com/gorilla/mux c9e326e2bdec29039a3761c07bece13133863e1e
github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478 github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
github.com/hpcloud/tail b2940955ab8b26e19d43a43c4da0475dd81bdb56 github.com/hpcloud/tail b2940955ab8b26e19d43a43c4da0475dd81bdb56
github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da
github.com/influxdata/influxdb e094138084855d444195b252314dfee9eae34cab github.com/influxdata/influxdb 21db76b3374c733f37ed16ad93f3484020034351
github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0 github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0
github.com/klauspost/crc32 19b0b332c9e4516a6370a0456e6182c3b5036720 github.com/klauspost/crc32 19b0b332c9e4516a6370a0456e6182c3b5036720
github.com/lib/pq e182dc4027e2ded4b19396d638610f2653295f36 github.com/lib/pq e182dc4027e2ded4b19396d638610f2653295f36
@@ -42,7 +42,7 @@ github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common e8eabff8812b05acf522b45fdcd725a785188e37 github.com/prometheus/common e8eabff8812b05acf522b45fdcd725a785188e37
github.com/prometheus/procfs 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8 github.com/prometheus/procfs 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8
github.com/samuel/go-zookeeper 218e9c81c0dd8b3b18172b2bbfad92cc7d6db55f github.com/samuel/go-zookeeper 218e9c81c0dd8b3b18172b2bbfad92cc7d6db55f
github.com/shirou/gopsutil 37d89088411de59a4ef9fc340afa0e89dfcb4ea9 github.com/shirou/gopsutil 1f32ce1bb380845be7f5d174ac641a2c592c0c42
github.com/soniah/gosnmp b1b4f885b12c5dcbd021c5cee1c904110de6db7d github.com/soniah/gosnmp b1b4f885b12c5dcbd021c5cee1c904110de6db7d
github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744 github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744
github.com/stretchr/testify 1f4a1643a57e798696635ea4c126e9127adb7d3c github.com/stretchr/testify 1f4a1643a57e798696635ea4c126e9127adb7d3c

View File

@@ -14,21 +14,21 @@ windows: prepare-windows build-windows
# Only run the build (no dependency grabbing) # Only run the build (no dependency grabbing)
build: build:
go install -ldflags "-X main.version=$(VERSION)" ./... go install -ldflags "-X main.Version=$(VERSION)" ./...
build-windows: build-windows:
go build -o telegraf.exe -ldflags \ go build -o telegraf.exe -ldflags \
"-X main.version=$(VERSION)" \ "-X main.Version=$(VERSION)" \
./cmd/telegraf/telegraf.go ./cmd/telegraf/telegraf.go
build-for-docker: build-for-docker:
CGO_ENABLED=0 GOOS=linux go build -installsuffix cgo -o telegraf -ldflags \ CGO_ENABLED=0 GOOS=linux go build -installsuffix cgo -o telegraf -ldflags \
"-s -X main.version=$(VERSION)" \ "-s -X main.Version=$(VERSION)" \
./cmd/telegraf/telegraf.go ./cmd/telegraf/telegraf.go
# Build with race detector # Build with race detector
dev: prepare dev: prepare
go build -race -ldflags "-X main.version=$(VERSION)" ./... go build -race -ldflags "-X main.Version=$(VERSION)" ./...
# run package script # run package script
package: package:

View File

@@ -20,12 +20,12 @@ new plugins.
### Linux deb and rpm Packages: ### Linux deb and rpm Packages:
Latest: Latest:
* https://dl.influxdata.com/telegraf/releases/telegraf_0.13.0-1_amd64.deb * http://get.influxdb.org/telegraf/telegraf_0.12.1-1_amd64.deb
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1.x86_64.rpm * http://get.influxdb.org/telegraf/telegraf-0.12.1-1.x86_64.rpm
Latest (arm): Latest (arm):
* https://dl.influxdata.com/telegraf/releases/telegraf_0.13.0-1_armhf.deb * http://get.influxdb.org/telegraf/telegraf_0.12.1-1_armhf.deb
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1.armhf.rpm * http://get.influxdb.org/telegraf/telegraf-0.12.1-1.armhf.rpm
##### Package Instructions: ##### Package Instructions:
@@ -46,28 +46,28 @@ to use this repo to install & update telegraf.
### Linux tarballs: ### Linux tarballs:
Latest: Latest:
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_linux_amd64.tar.gz * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_linux_amd64.tar.gz
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_linux_i386.tar.gz * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_linux_i386.tar.gz
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_linux_armhf.tar.gz * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_linux_armhf.tar.gz
##### tarball Instructions: ##### tarball Instructions:
To install the full directory structure with config file, run: To install the full directory structure with config file, run:
``` ```
sudo tar -C / -zxvf ./telegraf-0.13.0-1_linux_amd64.tar.gz sudo tar -C / -zxvf ./telegraf-0.12.1-1_linux_amd64.tar.gz
``` ```
To extract only the binary, run: To extract only the binary, run:
``` ```
tar -zxvf telegraf-0.13.0-1_linux_amd64.tar.gz --strip-components=3 ./usr/bin/telegraf tar -zxvf telegraf-0.12.1-1_linux_amd64.tar.gz --strip-components=3 ./usr/bin/telegraf
``` ```
### FreeBSD tarball: ### FreeBSD tarball:
Latest: Latest:
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_freebsd_amd64.tar.gz * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_freebsd_amd64.tar.gz
##### tarball Instructions: ##### tarball Instructions:
@@ -87,8 +87,8 @@ brew install telegraf
### Windows Binaries (EXPERIMENTAL) ### Windows Binaries (EXPERIMENTAL)
Latest: Latest:
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_windows_amd64.zip * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_windows_amd64.zip
* https://dl.influxdata.com/telegraf/releases/telegraf-0.13.0-1_windows_i386.zip * http://get.influxdb.org/telegraf/telegraf-0.12.1-1_windows_i386.zip
### From Source: ### From Source:

View File

@@ -46,13 +46,9 @@ var fOutputFiltersLegacy = flag.String("outputfilter", "",
var fConfigDirectoryLegacy = flag.String("configdirectory", "", var fConfigDirectoryLegacy = flag.String("configdirectory", "",
"directory containing additional *.conf files") "directory containing additional *.conf files")
// Telegraf version, populated linker. // Telegraf version
// ie, -ldflags "-X main.version=`git describe --always --tags`" // -ldflags "-X main.Version=`git describe --always --tags`"
var ( var Version string
version string
commit string
branch string
)
const usage = `Telegraf, The plugin-driven server agent for collecting and reporting metrics. const usage = `Telegraf, The plugin-driven server agent for collecting and reporting metrics.
@@ -136,7 +132,7 @@ func main() {
if len(args) > 0 { if len(args) > 0 {
switch args[0] { switch args[0] {
case "version": case "version":
v := fmt.Sprintf("Telegraf - version %s", version) v := fmt.Sprintf("Telegraf - Version %s", Version)
fmt.Println(v) fmt.Println(v)
return return
case "config": case "config":
@@ -162,7 +158,7 @@ func main() {
} }
if *fVersion { if *fVersion {
v := fmt.Sprintf("Telegraf - version %s", version) v := fmt.Sprintf("Telegraf - Version %s", Version)
fmt.Println(v) fmt.Println(v)
return return
} }
@@ -255,7 +251,7 @@ func main() {
} }
}() }()
log.Printf("Starting Telegraf (version %s)\n", version) log.Printf("Starting Telegraf (version %s)\n", Version)
log.Printf("Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) log.Printf("Loaded outputs: %s", strings.Join(c.OutputNames(), " "))
log.Printf("Loaded inputs: %s", strings.Join(c.InputNames(), " ")) log.Printf("Loaded inputs: %s", strings.Join(c.InputNames(), " "))
log.Printf("Tags enabled: %s", c.ListTags()) log.Printf("Tags enabled: %s", c.ListTags())

View File

@@ -638,8 +638,8 @@
# #
# ## If no servers are specified, then default to 127.0.0.1:1936 # ## If no servers are specified, then default to 127.0.0.1:1936
# servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"] # servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"]
# ## Or you can also use local socket # ## Or you can also use local socket(not work yet)
# ## servers = ["socket:/run/haproxy/admin.sock"] # ## servers = ["socket://run/haproxy/admin.sock"]
# # HTTP/HTTPS request given an address a method and a timeout # # HTTP/HTTPS request given an address a method and a timeout

View File

@@ -19,6 +19,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/haproxy" _ "github.com/influxdata/telegraf/plugins/inputs/haproxy"
_ "github.com/influxdata/telegraf/plugins/inputs/http_response" _ "github.com/influxdata/telegraf/plugins/inputs/http_response"
_ "github.com/influxdata/telegraf/plugins/inputs/httpjson" _ "github.com/influxdata/telegraf/plugins/inputs/httpjson"
_ "github.com/influxdata/telegraf/plugins/inputs/igloo"
_ "github.com/influxdata/telegraf/plugins/inputs/influxdb" _ "github.com/influxdata/telegraf/plugins/inputs/influxdb"
_ "github.com/influxdata/telegraf/plugins/inputs/ipmi_sensor" _ "github.com/influxdata/telegraf/plugins/inputs/ipmi_sensor"
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia" _ "github.com/influxdata/telegraf/plugins/inputs/jolokia"

View File

@@ -307,11 +307,7 @@ func gatherContainerStats(
for i, percpu := range stat.CPUStats.CPUUsage.PercpuUsage { for i, percpu := range stat.CPUStats.CPUUsage.PercpuUsage {
percputags := copyTags(tags) percputags := copyTags(tags)
percputags["cpu"] = fmt.Sprintf("cpu%d", i) percputags["cpu"] = fmt.Sprintf("cpu%d", i)
fields := map[string]interface{}{ acc.AddFields("docker_container_cpu", map[string]interface{}{"usage_total": percpu}, percputags, now)
"usage_total": percpu,
"container_id": id,
}
acc.AddFields("docker_container_cpu", fields, percputags, now)
} }
for network, netstats := range stat.Networks { for network, netstats := range stat.Networks {
@@ -470,8 +466,6 @@ func parseSize(sizeStr string) (int64, error) {
func init() { func init() {
inputs.Add("docker", func() telegraf.Input { inputs.Add("docker", func() telegraf.Input {
return &Docker{ return &Docker{}
Timeout: internal.Duration{Duration: time.Second * 5},
}
}) })
} }

View File

@@ -112,14 +112,12 @@ func TestDockerGatherContainerStats(t *testing.T) {
cputags["cpu"] = "cpu0" cputags["cpu"] = "cpu0"
cpu0fields := map[string]interface{}{ cpu0fields := map[string]interface{}{
"usage_total": uint64(1), "usage_total": uint64(1),
"container_id": "123456789",
} }
acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu0fields, cputags) acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu0fields, cputags)
cputags["cpu"] = "cpu1" cputags["cpu"] = "cpu1"
cpu1fields := map[string]interface{}{ cpu1fields := map[string]interface{}{
"usage_total": uint64(1002), "usage_total": uint64(1002),
"container_id": "123456789",
} }
acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu1fields, cputags) acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu1fields, cputags)
} }
@@ -375,7 +373,6 @@ func TestDockerGatherInfo(t *testing.T) {
"docker_container_cpu", "docker_container_cpu",
map[string]interface{}{ map[string]interface{}{
"usage_total": uint64(1231652), "usage_total": uint64(1231652),
"container_id": "b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173",
}, },
map[string]string{ map[string]string{
"container_name": "etcd2", "container_name": "etcd2",

View File

@@ -0,0 +1,23 @@
# igloo Input Plugin
The igloo plugin "tails" a logfile and parses each log message.
By default, the igloo plugin acts like the following unix tail command:
```
tail -F --lines=0 myfile.log
```
- `-F` means that it will follow the _name_ of the given file, so
that it will be compatible with log-rotated files, and that it will retry on
inaccessible files.
- `--lines=0` means that it will start at the end of the file (unless
the `from_beginning` option is set).
see http://man7.org/linux/man-pages/man1/tail.1.html for more details.
### Configuration:
```toml
```

View File

@@ -0,0 +1,331 @@
package igloo
import (
"fmt"
"log"
"regexp"
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/hpcloud/tail"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal/globpath"
"github.com/influxdata/telegraf/plugins/inputs"
)
// format of timestamps
const (
rfcFormat string = "%s-%s-%sT%s:%s:%s.%sZ"
)
var (
// regex for finding timestamps
tRe = regexp.MustCompile(`Timestamp=((\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}),(\d+))`)
)
type Tail struct {
Files []string
FromBeginning bool
TagKeys []string
Counters []string
NumFields []string
StrFields []string
numfieldsRe map[string]*regexp.Regexp
strfieldsRe map[string]*regexp.Regexp
countersRe map[string]*regexp.Regexp
tagsRe map[string]*regexp.Regexp
counters map[string]map[string]int64
tailers []*tail.Tail
wg sync.WaitGroup
acc telegraf.Accumulator
sync.Mutex
}
func NewTail() *Tail {
return &Tail{
FromBeginning: false,
}
}
const sampleConfig = `
## logfiles to parse.
##
## These accept standard unix glob matching rules, but with the addition of
## ** as a "super asterisk". ie:
## "/var/log/**.log" -> recursively find all .log files in /var/log
## "/var/log/*/*.log" -> find all .log files with a parent dir in /var/log
## "/var/log/apache.log" -> just tail the apache log file
##
## See https://github.com/gobwas/glob for more examples
##
files = ["$HOME/sample.log"]
## Read file from beginning.
from_beginning = false
## Each log message is searched for these tag keys in TagKey=Value format.
## Any that are found will be tagged on the resulting influx measurements.
tag_keys = [
"HostLocal",
"ProductName",
"OperationName",
]
## counters are keys which are treated as counters.
## so if counters = ["Result"], then this means that the following ocurrence
## on a log line:
## Result=Success
## would be treated as a counter: Result_Success, and it will be incremented
## for every occurrence, until Telegraf is restarted.
counters = ["Result"]
## num_fields are log line occurrences that are translated into numerical
## fields. ie:
## Duration=1
num_fields = ["Duration", "Attempt"]
## str_fields are log line occurences that are translated into string fields,
## ie:
## ActivityGUID=0bb03bf4-ae1d-4487-bb6f-311653b35760
str_fields = ["ActivityGUID"]
`
func (t *Tail) SampleConfig() string {
return sampleConfig
}
func (t *Tail) Description() string {
return "Stream an igloo file, like the tail -f command"
}
func (t *Tail) Gather(acc telegraf.Accumulator) error {
return nil
}
func (t *Tail) buildRegexes() error {
t.numfieldsRe = make(map[string]*regexp.Regexp)
t.strfieldsRe = make(map[string]*regexp.Regexp)
t.tagsRe = make(map[string]*regexp.Regexp)
t.countersRe = make(map[string]*regexp.Regexp)
t.counters = make(map[string]map[string]int64)
for _, field := range t.NumFields {
re, err := regexp.Compile(field + `=([0-9\.]+)`)
if err != nil {
return err
}
t.numfieldsRe[field] = re
}
for _, field := range t.StrFields {
re, err := regexp.Compile(field + `=([0-9a-zA-Z\.\-]+)`)
if err != nil {
return err
}
t.strfieldsRe[field] = re
}
for _, field := range t.TagKeys {
re, err := regexp.Compile(field + `=([0-9a-zA-Z\.\-]+)`)
if err != nil {
return err
}
t.tagsRe[field] = re
}
for _, field := range t.Counters {
re, err := regexp.Compile("(" + field + ")" + `=([0-9a-zA-Z\.\-]+)`)
if err != nil {
return err
}
t.countersRe[field] = re
}
return nil
}
func (t *Tail) Start(acc telegraf.Accumulator) error {
t.Lock()
defer t.Unlock()
t.acc = acc
if err := t.buildRegexes(); err != nil {
return err
}
var seek tail.SeekInfo
if !t.FromBeginning {
seek.Whence = 2
seek.Offset = 0
}
var errS string
// Create a "tailer" for each file
for _, filepath := range t.Files {
g, err := globpath.Compile(filepath)
if err != nil {
log.Printf("ERROR Glob %s failed to compile, %s", filepath, err)
}
for file, _ := range g.Match() {
tailer, err := tail.TailFile(file,
tail.Config{
ReOpen: true,
Follow: true,
Location: &seek,
})
if err != nil {
errS += err.Error() + " "
continue
}
// create a goroutine for each "tailer"
go t.receiver(tailer)
t.tailers = append(t.tailers, tailer)
}
}
if errS != "" {
return fmt.Errorf(errS)
}
return nil
}
// this is launched as a goroutine to continuously watch a tailed logfile
// for changes, parse any incoming msgs, and add to the accumulator.
func (t *Tail) receiver(tailer *tail.Tail) {
t.wg.Add(1)
defer t.wg.Done()
var err error
var line *tail.Line
for line = range tailer.Lines {
if line.Err != nil {
log.Printf("ERROR tailing file %s, Error: %s\n",
tailer.Filename, err)
continue
}
err = t.Parse(line.Text)
if err != nil {
log.Printf("ERROR: %s", err)
}
}
}
func (t *Tail) Parse(line string) error {
// find the timestamp:
match := tRe.FindAllStringSubmatch(line, -1)
if len(match) < 1 {
return nil
}
if len(match[0]) < 9 {
return nil
}
// make an rfc3339 timestamp and parse it:
ts, err := time.Parse(time.RFC3339Nano,
fmt.Sprintf(rfcFormat, match[0][2], match[0][3], match[0][4], match[0][5], match[0][6], match[0][7], match[0][8]))
if err != nil {
return nil
}
fields := make(map[string]interface{})
tags := make(map[string]string)
// parse numerical fields:
for name, re := range t.numfieldsRe {
match := re.FindAllStringSubmatch(line, -1)
if len(match) < 1 {
continue
}
if len(match[0]) < 2 {
continue
}
num, err := strconv.ParseFloat(match[0][1], 64)
if err == nil {
fields[name] = num
}
}
// parse string fields:
for name, re := range t.strfieldsRe {
match := re.FindAllStringSubmatch(line, -1)
if len(match) < 1 {
continue
}
if len(match[0]) < 2 {
continue
}
fields[name] = match[0][1]
}
// parse tags:
for name, re := range t.tagsRe {
match := re.FindAllStringSubmatch(line, -1)
if len(match) < 1 {
continue
}
if len(match[0]) < 2 {
continue
}
tags[name] = match[0][1]
}
if len(t.countersRe) > 0 {
// Make a unique key for the measurement name/tags
var tg []string
for k, v := range tags {
tg = append(tg, fmt.Sprintf("%s=%s", k, v))
}
sort.Strings(tg)
hash := fmt.Sprintf("%s%s", strings.Join(tg, ""), "igloo")
// check if this hash already has a counter map
_, ok := t.counters[hash]
if !ok {
// doesnt have counter map, so make one
t.counters[hash] = make(map[string]int64)
}
// search for counter matches:
for _, re := range t.countersRe {
match := re.FindAllStringSubmatch(line, -1)
if len(match) < 1 {
continue
}
if len(match[0]) < 3 {
continue
}
counterName := match[0][1] + "_" + match[0][2]
// increment this counter
t.counters[hash][counterName] += 1
// add this counter to the output fields
fields[counterName] = t.counters[hash][counterName]
}
}
t.acc.AddFields("igloo", fields, tags, ts)
return nil
}
func (t *Tail) Stop() {
t.Lock()
defer t.Unlock()
for _, t := range t.tailers {
err := t.Stop()
if err != nil {
log.Printf("ERROR stopping tail on file %s\n", t.Filename)
}
t.Cleanup()
}
t.wg.Wait()
}
func init() {
inputs.Add("igloo", func() telegraf.Input {
return NewTail()
})
}

View File

@@ -21,12 +21,8 @@ The plugin expects messages in the
"sensors/#", "sensors/#",
] ]
# if true, messages that can't be delivered while the subscriber is offline ## Maximum number of metrics to buffer between collection intervals
# will be delivered when it comes back (such as on service restart). metric_buffer = 100000
# NOTE: if true, client_id MUST be set
persistent_session = false
# If empty, a random client ID will be generated.
client_id = ""
## username and password to connect MQTT server. ## username and password to connect MQTT server.
# username = "telegraf" # username = "telegraf"

View File

@@ -26,6 +26,9 @@ type Snmp struct {
nameToOid map[string]string nameToOid map[string]string
initNode Node initNode Node
subTableMap map[string]Subtable subTableMap map[string]Subtable
// TODO change as unexportable
//OidInstanceMapping map[string]map[string]string
} }
type Host struct { type Host struct {
@@ -50,8 +53,6 @@ type Host struct {
// array of processed oids // array of processed oids
// to skip oid duplication // to skip oid duplication
processedOids []string processedOids []string
OidInstanceMapping map[string]map[string]string
} }
type Table struct { type Table struct {
@@ -115,6 +116,9 @@ type Node struct {
subnodes map[string]Node subnodes map[string]Node
} }
// TODO move this var to snmp struct
var OidInstanceMapping = make(map[string]map[string]string)
var sampleConfig = ` var sampleConfig = `
## Use 'oids.txt' file to translate oids to names ## Use 'oids.txt' file to translate oids to names
## To generate 'oids.txt' you need to run: ## To generate 'oids.txt' you need to run:
@@ -392,7 +396,7 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
// TODO save mapping and computed oids // TODO save mapping and computed oids
// to do it only the first time // to do it only the first time
// only if len(s.OidInstanceMapping) == 0 // only if len(s.OidInstanceMapping) == 0
if len(host.OidInstanceMapping) >= 0 { if len(OidInstanceMapping) >= 0 {
if err := host.SNMPMap(acc, s.nameToOid, s.subTableMap); err != nil { if err := host.SNMPMap(acc, s.nameToOid, s.subTableMap); err != nil {
log.Printf("SNMP Mapping error for host '%s': %s", host.Address, err) log.Printf("SNMP Mapping error for host '%s': %s", host.Address, err)
continue continue
@@ -409,14 +413,7 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
return nil return nil
} }
func (h *Host) SNMPMap( func (h *Host) SNMPMap(acc telegraf.Accumulator, nameToOid map[string]string, subTableMap map[string]Subtable) error {
acc telegraf.Accumulator,
nameToOid map[string]string,
subTableMap map[string]Subtable,
) error {
if h.OidInstanceMapping == nil {
h.OidInstanceMapping = make(map[string]map[string]string)
}
// Get snmp client // Get snmp client
snmpClient, err := h.GetSNMPClient() snmpClient, err := h.GetSNMPClient()
if err != nil { if err != nil {
@@ -526,11 +523,11 @@ func (h *Host) SNMPMap(
// Building mapping table // Building mapping table
mapping := map[string]string{strings.Trim(key, "."): string(variable.Value.([]byte))} mapping := map[string]string{strings.Trim(key, "."): string(variable.Value.([]byte))}
_, exists := h.OidInstanceMapping[table.oid] _, exists := OidInstanceMapping[table.oid]
if exists { if exists {
h.OidInstanceMapping[table.oid][strings.Trim(key, ".")] = string(variable.Value.([]byte)) OidInstanceMapping[table.oid][strings.Trim(key, ".")] = string(variable.Value.([]byte))
} else { } else {
h.OidInstanceMapping[table.oid] = mapping OidInstanceMapping[table.oid] = mapping
} }
// Add table oid in bulk oid list // Add table oid in bulk oid list
@@ -723,12 +720,7 @@ func (h *Host) GetSNMPClient() (*gosnmp.GoSNMP, error) {
return snmpClient, nil return snmpClient, nil
} }
func (h *Host) HandleResponse( func (h *Host) HandleResponse(oids map[string]Data, result *gosnmp.SnmpPacket, acc telegraf.Accumulator, initNode Node) (string, error) {
oids map[string]Data,
result *gosnmp.SnmpPacket,
acc telegraf.Accumulator,
initNode Node,
) (string, error) {
var lastOid string var lastOid string
for _, variable := range result.Variables { for _, variable := range result.Variables {
lastOid = variable.Name lastOid = variable.Name
@@ -763,7 +755,7 @@ func (h *Host) HandleResponse(
strings.Split(string(variable.Name[1:]), ".")) strings.Split(string(variable.Name[1:]), "."))
// Set instance tag // Set instance tag
// From mapping table // From mapping table
mapping, inMappingNoSubTable := h.OidInstanceMapping[oid_key] mapping, inMappingNoSubTable := OidInstanceMapping[oid_key]
if inMappingNoSubTable { if inMappingNoSubTable {
// filter if the instance in not in // filter if the instance in not in
// OidInstanceMapping mapping map // OidInstanceMapping mapping map
@@ -792,7 +784,7 @@ func (h *Host) HandleResponse(
// Because the result oid is equal to inputs.snmp.get section // Because the result oid is equal to inputs.snmp.get section
field_name = oid.Name field_name = oid.Name
} }
tags["snmp_host"], _, _ = net.SplitHostPort(h.Address) tags["host"], _, _ = net.SplitHostPort(h.Address)
fields := make(map[string]interface{}) fields := make(map[string]interface{})
fields[string(field_name)] = variable.Value fields[string(field_name)] = variable.Value

View File

@@ -103,7 +103,7 @@ func TestSNMPGet1(t *testing.T) {
}, },
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -141,7 +141,7 @@ func TestSNMPGet2(t *testing.T) {
}, },
map[string]string{ map[string]string{
"instance": "0", "instance": "0",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -182,7 +182,7 @@ func TestSNMPGet3(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "1", "instance": "1",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -224,7 +224,7 @@ func TestSNMPEasyGet4(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "1", "instance": "1",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -235,7 +235,7 @@ func TestSNMPEasyGet4(t *testing.T) {
}, },
map[string]string{ map[string]string{
"instance": "0", "instance": "0",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -277,7 +277,7 @@ func TestSNMPEasyGet5(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "1", "instance": "1",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -288,7 +288,7 @@ func TestSNMPEasyGet5(t *testing.T) {
}, },
map[string]string{ map[string]string{
"instance": "0", "instance": "0",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -321,7 +321,7 @@ func TestSNMPEasyGet6(t *testing.T) {
}, },
map[string]string{ map[string]string{
"instance": "0", "instance": "0",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -362,7 +362,7 @@ func TestSNMPBulk1(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "1", "instance": "1",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -374,7 +374,7 @@ func TestSNMPBulk1(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "2", "instance": "2",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -386,7 +386,7 @@ func TestSNMPBulk1(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "3", "instance": "3",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -398,7 +398,7 @@ func TestSNMPBulk1(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "36", "instance": "36",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }
@@ -440,7 +440,7 @@ func dTestSNMPBulk2(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "1", "instance": "1",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -452,7 +452,7 @@ func dTestSNMPBulk2(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "2", "instance": "2",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -464,7 +464,7 @@ func dTestSNMPBulk2(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "3", "instance": "3",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
@@ -476,7 +476,7 @@ func dTestSNMPBulk2(t *testing.T) {
map[string]string{ map[string]string{
"unit": "octets", "unit": "octets",
"instance": "36", "instance": "36",
"snmp_host": testutil.GetLocalHost(), "host": testutil.GetLocalHost(),
}, },
) )
} }

View File

@@ -70,7 +70,6 @@ func getEmptyFields() map[string]interface{} {
"running": int64(0), "running": int64(0),
"sleeping": int64(0), "sleeping": int64(0),
"total": int64(0), "total": int64(0),
"unknown": int64(0),
} }
switch runtime.GOOS { switch runtime.GOOS {
case "freebsd": case "freebsd":
@@ -115,8 +114,6 @@ func (p *Processes) gatherFromPS(fields map[string]interface{}) error {
fields["sleeping"] = fields["sleeping"].(int64) + int64(1) fields["sleeping"] = fields["sleeping"].(int64) + int64(1)
case 'I': case 'I':
fields["idle"] = fields["idle"].(int64) + int64(1) fields["idle"] = fields["idle"].(int64) + int64(1)
case '?':
fields["unknown"] = fields["unknown"].(int64) + int64(1)
default: default:
log.Printf("processes: Unknown state [ %s ] from ps", log.Printf("processes: Unknown state [ %s ] from ps",
string(status[0])) string(status[0]))

View File

@@ -132,16 +132,13 @@ def create_package_fs(build_root):
os.makedirs(os.path.join(build_root, d)) os.makedirs(os.path.join(build_root, d))
os.chmod(os.path.join(build_root, d), 0o755) os.chmod(os.path.join(build_root, d), 0o755)
def package_scripts(build_root, config_only=False, windows=False): def package_scripts(build_root, windows=False):
"""Copy the necessary scripts and configuration files to the package """Copy the necessary scripts and configuration files to the package
filesystem. filesystem.
""" """
if config_only or windows:
logging.info("Copying configuration to build directory")
if windows: if windows:
logging.info("Copying configuration to build directory.")
shutil.copyfile(DEFAULT_WINDOWS_CONFIG, os.path.join(build_root, "telegraf.conf")) shutil.copyfile(DEFAULT_WINDOWS_CONFIG, os.path.join(build_root, "telegraf.conf"))
else:
shutil.copyfile(DEFAULT_CONFIG, os.path.join(build_root, "telegraf.conf"))
os.chmod(os.path.join(build_root, "telegraf.conf"), 0o644) os.chmod(os.path.join(build_root, "telegraf.conf"), 0o644)
else: else:
logging.info("Copying scripts and configuration to build directory") logging.info("Copying scripts and configuration to build directory")
@@ -242,15 +239,21 @@ def get_current_version():
"""Parse version information from git tag output. """Parse version information from git tag output.
""" """
version_tag = get_current_version_tag() version_tag = get_current_version_tag()
# Remove leading 'v' # Remove leading 'v' and possible '-rc\d+'
if version_tag[0] == 'v': if version_tag[0] == 'v':
version_tag = version_tag[1:] version_tag = version_tag[1:]
# Replace any '-'/'_' with '~' version = re.sub(r'-rc\d+', '', str(version_tag))
if '-' in version_tag: return version
version_tag = version_tag.replace("-","~")
if '_' in version_tag: def get_current_rc():
version_tag = version_tag.replace("_","~") """Parse release candidate from git tag output.
return version_tag """
rc = None
version_tag = get_current_version_tag()
matches = re.match(r'.*-rc(\d+)', str(version_tag))
if matches:
rc, = matches.groups(1)
return rc
def get_current_commit(short=False): def get_current_commit(short=False):
"""Retrieve the current git commit. """Retrieve the current git commit.
@@ -415,6 +418,7 @@ def build(version=None,
platform=None, platform=None,
arch=None, arch=None,
nightly=False, nightly=False,
rc=None,
race=False, race=False,
clean=False, clean=False,
outdir=".", outdir=".",
@@ -441,6 +445,9 @@ def build(version=None,
shutil.rmtree(outdir) shutil.rmtree(outdir)
os.makedirs(outdir) os.makedirs(outdir)
if rc:
# If a release candidate, update the version information accordingly
version = "{}rc{}".format(version, rc)
logging.info("Using version '{}' for build.".format(version)) logging.info("Using version '{}' for build.".format(version))
tmp_build_dir = create_temp_dir() tmp_build_dir = create_temp_dir()
@@ -533,7 +540,7 @@ def generate_sig_from_file(path):
run('gpg --armor --detach-sign --yes {}'.format(path)) run('gpg --armor --detach-sign --yes {}'.format(path))
return True return True
def package(build_output, pkg_name, version, nightly=False, iteration=1, static=False, release=False): def package(build_output, version, nightly=False, rc=None, iteration=1, static=False, release=False):
"""Package the output of the build process. """Package the output of the build process.
""" """
outfiles = [] outfiles = []
@@ -557,12 +564,10 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
os.makedirs(build_root) os.makedirs(build_root)
# Copy packaging scripts to build directory # Copy packaging scripts to build directory
if platform == "windows": if platform == "windows" or static or "static_" in arch:
# For windows and static builds, just copy # For windows and static builds, just copy
# binaries to root of package (no other scripts or # binaries to root of package (no other scripts or
# directories) # directories)
package_scripts(build_root, config_only=True, windows=True)
elif static or "static_" in arch:
package_scripts(build_root, config_only=True) package_scripts(build_root, config_only=True)
else: else:
create_package_fs(build_root) create_package_fs(build_root)
@@ -587,7 +592,7 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
for package_type in supported_packages[platform]: for package_type in supported_packages[platform]:
# Package the directory structure for each package type for the platform # Package the directory structure for each package type for the platform
logging.debug("Packaging directory '{}' as '{}'.".format(build_root, package_type)) logging.debug("Packaging directory '{}' as '{}'.".format(build_root, package_type))
name = pkg_name name = PACKAGE_NAME
# Reset version, iteration, and current location on each run # Reset version, iteration, and current location on each run
# since they may be modified below. # since they may be modified below.
package_version = version package_version = version
@@ -599,12 +604,17 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
package_arch = arch package_arch = arch
if not release and not nightly: if not release and not nightly:
# For non-release builds, just use the commit hash as the version # For non-release builds, just use the commit hash as the version
package_version = "{}~{}".format(version, package_version = "{}~{}.{}".format(version,
get_current_branch(),
get_current_commit(short=True)) get_current_commit(short=True))
package_iteration = "0" package_iteration = "0"
package_build_root = build_root package_build_root = build_root
current_location = build_output[platform][arch] current_location = build_output[platform][arch]
if rc is not None and release:
# Set iteration to 0 since it's a release candidate
package_iteration = "0.rc{}".format(rc)
if package_type in ['zip', 'tar']: if package_type in ['zip', 'tar']:
# For tars and zips, start the packaging one folder above # For tars and zips, start the packaging one folder above
# the build root (to include the package name) # the build root (to include the package name)
@@ -629,17 +639,18 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
package_version, package_version,
platform, platform,
package_arch) package_arch)
current_location = os.path.join(os.getcwd(), current_location) current_location = os.path.join(os.getcwd(), current_location)
if package_type == 'tar': if package_type == 'tar':
tar_command = "cd {} && tar -cvzf {}.tar.gz ./*".format(package_build_root, name) tar_command = "cd {} && tar -cvzf {}.tar.gz ./*".format(build_root, name)
run(tar_command, shell=True) run(tar_command, shell=True)
run("mv {}.tar.gz {}".format(os.path.join(package_build_root, name), current_location), shell=True) run("mv {}.tar.gz {}".format(os.path.join(build_root, name), current_location), shell=True)
outfile = os.path.join(current_location, name + ".tar.gz") outfile = os.path.join(current_location, name + ".tar.gz")
outfiles.append(outfile) outfiles.append(outfile)
elif package_type == 'zip': elif package_type == 'zip':
zip_command = "cd {} && zip -r {}.zip ./*".format(package_build_root, name) zip_command = "cd {} && zip -r {}.zip ./*".format(build_root, name)
run(zip_command, shell=True) run(zip_command, shell=True)
run("mv {}.zip {}".format(os.path.join(package_build_root, name), current_location), shell=True) run("mv {}.zip {}".format(os.path.join(build_root, name), current_location), shell=True)
outfile = os.path.join(current_location, name + ".zip") outfile = os.path.join(current_location, name + ".zip")
outfiles.append(outfile) outfiles.append(outfile)
elif package_type not in ['zip', 'tar'] and static or "static_" in arch: elif package_type not in ['zip', 'tar'] and static or "static_" in arch:
@@ -670,6 +681,7 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
os.rename(outfile, new_outfile) os.rename(outfile, new_outfile)
outfile = new_outfile outfile = new_outfile
else: else:
# Strip iteration from package name
if package_type == 'rpm': if package_type == 'rpm':
# rpm's convert any dashes to underscores # rpm's convert any dashes to underscores
package_version = package_version.replace("-", "_") package_version = package_version.replace("-", "_")
@@ -686,6 +698,9 @@ def package(build_output, pkg_name, version, nightly=False, iteration=1, static=
def main(args): def main(args):
global PACKAGE_NAME global PACKAGE_NAME
if args.nightly and args.rc:
logging.error("Cannot be both a nightly and a release candidate.")
return 1
if args.release and args.nightly: if args.release and args.nightly:
logging.error("Cannot be both a nightly and a release.") logging.error("Cannot be both a nightly and a release.")
return 1 return 1
@@ -695,6 +710,8 @@ def main(args):
args.version = "{}~n{}".format(args.version, args.version = "{}~n{}".format(args.version,
datetime.utcnow().strftime("%Y%m%d%H%M")) datetime.utcnow().strftime("%Y%m%d%H%M"))
args.iteration = 0 args.iteration = 0
elif args.rc:
args.iteration = 0
# Pre-build checks # Pre-build checks
check_environ() check_environ()
@@ -761,6 +778,7 @@ def main(args):
platform=platform, platform=platform,
arch=arch, arch=arch,
nightly=args.nightly, nightly=args.nightly,
rc=args.rc,
race=args.race, race=args.race,
clean=args.clean, clean=args.clean,
outdir=od, outdir=od,
@@ -775,9 +793,9 @@ def main(args):
logging.error("FPM ruby gem required for packaging. Stopping.") logging.error("FPM ruby gem required for packaging. Stopping.")
return 1 return 1
packages = package(build_output, packages = package(build_output,
args.name,
args.version, args.version,
nightly=args.nightly, nightly=args.nightly,
rc=args.rc,
iteration=args.iteration, iteration=args.iteration,
static=args.static, static=args.static,
release=args.release) release=args.release)
@@ -826,7 +844,6 @@ if __name__ == '__main__':
help='Output directory') help='Output directory')
parser.add_argument('--name', '-n', parser.add_argument('--name', '-n',
metavar='<name>', metavar='<name>',
default=PACKAGE_NAME,
type=str, type=str,
help='Name to use for package name (when package is specified)') help='Name to use for package name (when package is specified)')
parser.add_argument('--arch', parser.add_argument('--arch',
@@ -854,10 +871,14 @@ if __name__ == '__main__':
type=str, type=str,
default=get_current_version(), default=get_current_version(),
help='Version information to apply to build output (ex: 0.12.0)') help='Version information to apply to build output (ex: 0.12.0)')
parser.add_argument('--rc',
metavar='<release candidate>',
type=int,
help='Release Candidate (RC) version to apply to build output')
parser.add_argument('--iteration', parser.add_argument('--iteration',
metavar='<package iteration>', metavar='<package iteration>',
type=str, type=int,
default="1", default=1,
help='Package iteration to apply to build output (defaults to 1)') help='Package iteration to apply to build output (defaults to 1)')
parser.add_argument('--stats', parser.add_argument('--stats',
action='store_true', action='store_true',