func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error { metrics := itemList{} // Both values are empty in normal use. if m.TestName != testObject { // Cleanup any handles before emptying the global variable containing valid queries. m.CleanupTestMode() gItemList = make(map[int]*item) testObject = m.TestName testConfigParsed = true configParsed = false } // We only need to parse the config during the init, it uses the global variable after. if configParsed == false { err := m.ParseConfig(&metrics) if err != nil { return err } } var bufSize uint32 var bufCount uint32 var size uint32 = uint32(unsafe.Sizeof(win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{})) var emptyBuf [1]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr. // For iterate over the known metrics and get the samples. for _, metric := range gItemList { // collect ret := win.PdhCollectQueryData(metric.handle) if ret == win.ERROR_SUCCESS { ret = win.PdhGetFormattedCounterArrayDouble(metric.counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN. if ret == win.PDH_MORE_DATA { filledBuf := make([]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size) ret = win.PdhGetFormattedCounterArrayDouble(metric.counterHandle, &bufSize, &bufCount, &filledBuf[0]) for i := 0; i < int(bufCount); i++ { c := filledBuf[i] var s string = win.UTF16PtrToString(c.SzName) var add bool if metric.include_total { // If IncludeTotal is set, include all. add = true } else if metric.instance == "*" && !strings.Contains(s, "_Total") { // Catch if set to * and that it is not a '*_Total*' instance. add = true } else if metric.instance == s { // Catch if we set it to total or some form of it add = true } else if metric.instance == "------" { add = true } if add { fields := make(map[string]interface{}) tags := make(map[string]string) if s != "" { tags["instance"] = s } tags["objectname"] = metric.objectName fields[string(metric.counter)] = float32(c.FmtValue.DoubleValue) var measurement string if metric.measurement == "" { measurement = "win_perf_counters" } else { measurement = metric.measurement } acc.AddFields(measurement, fields, tags) } } filledBuf = nil // Need to at least set bufSize to zero, because if not, the function will not // return PDH_MORE_DATA and will not set the bufSize. bufCount = 0 bufSize = 0 } } } return nil }
// Gathers data from a particular URL // Parameters: // acc : The telegraf Accumulator to use // url : endpoint to send request to // // Returns: // error: Any error that may have occurred func (i *InfluxDB) gatherURL( acc telegraf.Accumulator, url string, ) error { resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // It would be nice to be able to decode into a map[string]point, but // we'll get a decoder error like: // `json: cannot unmarshal array into Go value of type influxdb.point` // if any of the values aren't objects. // To avoid that error, we decode by hand. dec := json.NewDecoder(resp.Body) // Parse beginning of object if t, err := dec.Token(); err != nil { return err } else if t != json.Delim('{') { return errors.New("document root must be a JSON object") } // Loop through rest of object for { // Nothing left in this object, we're done if !dec.More() { break } // Read in a string key. We don't do anything with the top-level keys, so it's discarded. _, err := dec.Token() if err != nil { return err } // Attempt to parse a whole object into a point. // It might be a non-object, like a string or array. // If we fail to decode it into a point, ignore it and move on. var p point if err := dec.Decode(&p); err != nil { continue } // If the object was a point, but was not fully initialized, ignore it and move on. if p.Name == "" || p.Tags == nil || p.Values == nil || len(p.Values) == 0 { continue } // Add a tag to indicate the source of the data. p.Tags["url"] = url acc.AddFields( "influxdb_"+p.Name, p.Values, p.Tags, ) } return nil }