mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-23 21:26:36 +00:00
Bring the textfile collector over from node_exporter (#174)
Bring the textfile collector over from node_exporter This adds a slightly modified textfile collector from the official node_exporter project.
This commit is contained in:
committed by
Calle Pettersson
parent
5db7c0a936
commit
cf792394f3
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
*.exe
|
*.exe
|
||||||
VERSION
|
VERSION
|
||||||
|
*.swp
|
||||||
|
*.un~
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ process | [Win32_PerfRawData_PerfProc_Process](https://msdn.microsoft.com/en-us/
|
|||||||
service | [Win32_Service](https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx) metrics (service states) | ✓
|
service | [Win32_Service](https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx) metrics (service states) | ✓
|
||||||
system | Win32_PerfRawData_PerfOS_System metrics (system calls) | ✓
|
system | Win32_PerfRawData_PerfOS_System metrics (system calls) | ✓
|
||||||
tcp | [Win32_PerfRawData_Tcpip_TCPv4](https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx) metrics (tcp connections) |
|
tcp | [Win32_PerfRawData_Tcpip_TCPv4](https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx) metrics (tcp connections) |
|
||||||
|
textfile | Read prometheus metrics from a text file | ✓
|
||||||
vmware | Performance counters installed by the Vmware Guest agent |
|
vmware | Performance counters installed by the Vmware Guest agent |
|
||||||
|
|
||||||
The HELP texts shows the WMI data source, please see MSDN documentation for details.
|
The HELP texts shows the WMI data source, please see MSDN documentation for details.
|
||||||
@@ -39,6 +40,7 @@ Name | Description
|
|||||||
`LISTEN_ADDR` | The IP address to bind to. Defaults to 0.0.0.0
|
`LISTEN_ADDR` | The IP address to bind to. Defaults to 0.0.0.0
|
||||||
`LISTEN_PORT` | The port to bind to. Defaults to 9182.
|
`LISTEN_PORT` | The port to bind to. Defaults to 9182.
|
||||||
`METRICS_PATH` | The path at which to serve metrics. Defaults to `/metrics`
|
`METRICS_PATH` | The path at which to serve metrics. Defaults to `/metrics`
|
||||||
|
`TEXTFILE_DIR` | As the `--collector.textfile.directory` flag, provide a directory to read text files with metrics from
|
||||||
|
|
||||||
Parameters are sent to the installer via `msiexec`. Example invocation:
|
Parameters are sent to the installer via `msiexec`. Example invocation:
|
||||||
|
|
||||||
|
|||||||
255
collector/textfile.go
Normal file
255
collector/textfile.go
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
// Copyright 2015 The Prometheus Authors
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build !notextfile
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
"github.com/prometheus/common/expfmt"
|
||||||
|
"github.com/prometheus/common/log"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
textFileDirectory = kingpin.Flag(
|
||||||
|
"collector.textfile.directory",
|
||||||
|
"Directory to read text files with metrics from.",
|
||||||
|
).Default("C:\\Program Files\\wmi_exporter\\textfile_inputs").String()
|
||||||
|
|
||||||
|
mtimeDesc = prometheus.NewDesc(
|
||||||
|
"wmi_textfile_mtime_seconds",
|
||||||
|
"Unixtime mtime of textfiles successfully read.",
|
||||||
|
[]string{"file"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type textFileCollector struct {
|
||||||
|
path string
|
||||||
|
// Only set for testing to get predictable output.
|
||||||
|
mtime *float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Factories["textfile"] = NewTextFileCollector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTextFileCollector returns a new Collector exposing metrics read from files
|
||||||
|
// in the given textfile directory.
|
||||||
|
func NewTextFileCollector() (Collector, error) {
|
||||||
|
return &textFileCollector{
|
||||||
|
path: *textFileDirectory,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertMetricFamily(metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric) {
|
||||||
|
var valType prometheus.ValueType
|
||||||
|
var val float64
|
||||||
|
|
||||||
|
allLabelNames := map[string]struct{}{}
|
||||||
|
for _, metric := range metricFamily.Metric {
|
||||||
|
labels := metric.GetLabel()
|
||||||
|
for _, label := range labels {
|
||||||
|
if _, ok := allLabelNames[label.GetName()]; !ok {
|
||||||
|
allLabelNames[label.GetName()] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metric := range metricFamily.Metric {
|
||||||
|
if metric.TimestampMs != nil {
|
||||||
|
log.Warnf("Ignoring unsupported custom timestamp on textfile collector metric %v", metric)
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := metric.GetLabel()
|
||||||
|
var names []string
|
||||||
|
var values []string
|
||||||
|
for _, label := range labels {
|
||||||
|
names = append(names, label.GetName())
|
||||||
|
values = append(values, label.GetValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range allLabelNames {
|
||||||
|
present := false
|
||||||
|
for _, name := range names {
|
||||||
|
if k == name {
|
||||||
|
present = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if present == false {
|
||||||
|
names = append(names, k)
|
||||||
|
values = append(values, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metricType := metricFamily.GetType()
|
||||||
|
switch metricType {
|
||||||
|
case dto.MetricType_COUNTER:
|
||||||
|
valType = prometheus.CounterValue
|
||||||
|
val = metric.Counter.GetValue()
|
||||||
|
|
||||||
|
case dto.MetricType_GAUGE:
|
||||||
|
valType = prometheus.GaugeValue
|
||||||
|
val = metric.Gauge.GetValue()
|
||||||
|
|
||||||
|
case dto.MetricType_UNTYPED:
|
||||||
|
valType = prometheus.UntypedValue
|
||||||
|
val = metric.Untyped.GetValue()
|
||||||
|
|
||||||
|
case dto.MetricType_SUMMARY:
|
||||||
|
quantiles := map[float64]float64{}
|
||||||
|
for _, q := range metric.Summary.Quantile {
|
||||||
|
quantiles[q.GetQuantile()] = q.GetValue()
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstSummary(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
*metricFamily.Name,
|
||||||
|
metricFamily.GetHelp(),
|
||||||
|
names, nil,
|
||||||
|
),
|
||||||
|
metric.Summary.GetSampleCount(),
|
||||||
|
metric.Summary.GetSampleSum(),
|
||||||
|
quantiles, values...,
|
||||||
|
)
|
||||||
|
case dto.MetricType_HISTOGRAM:
|
||||||
|
buckets := map[float64]uint64{}
|
||||||
|
for _, b := range metric.Histogram.Bucket {
|
||||||
|
buckets[b.GetUpperBound()] = b.GetCumulativeCount()
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstHistogram(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
*metricFamily.Name,
|
||||||
|
metricFamily.GetHelp(),
|
||||||
|
names, nil,
|
||||||
|
),
|
||||||
|
metric.Histogram.GetSampleCount(),
|
||||||
|
metric.Histogram.GetSampleSum(),
|
||||||
|
buckets, values...,
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
log.Errorf("unknown metric type for file")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
*metricFamily.Name,
|
||||||
|
metricFamily.GetHelp(),
|
||||||
|
names, nil,
|
||||||
|
),
|
||||||
|
valType, val, values...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *textFileCollector) exportMTimes(mtimes map[string]time.Time, ch chan<- prometheus.Metric) {
|
||||||
|
// Export the mtimes of the successful files.
|
||||||
|
if len(mtimes) > 0 {
|
||||||
|
// Sorting is needed for predictable output comparison in tests.
|
||||||
|
filenames := make([]string, 0, len(mtimes))
|
||||||
|
for filename := range mtimes {
|
||||||
|
filenames = append(filenames, filename)
|
||||||
|
}
|
||||||
|
sort.Strings(filenames)
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
mtime := float64(mtimes[filename].UnixNano() / 1e9)
|
||||||
|
if c.mtime != nil {
|
||||||
|
mtime = *c.mtime
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(mtimeDesc, prometheus.GaugeValue, mtime, filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update implements the Collector interface.
|
||||||
|
func (c *textFileCollector) Collect(ch chan<- prometheus.Metric) error {
|
||||||
|
error := 0.0
|
||||||
|
mtimes := map[string]time.Time{}
|
||||||
|
|
||||||
|
// Iterate over files and accumulate their metrics.
|
||||||
|
files, err := ioutil.ReadDir(c.path)
|
||||||
|
if err != nil && c.path != "" {
|
||||||
|
log.Errorf("Error reading textfile collector directory %q: %s", c.path, err)
|
||||||
|
error = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLoop:
|
||||||
|
for _, f := range files {
|
||||||
|
if !strings.HasSuffix(f.Name(), ".prom") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path := filepath.Join(c.path, f.Name())
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error opening %q: %v", path, err)
|
||||||
|
error = 1.0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var parser expfmt.TextParser
|
||||||
|
parsedFamilies, err := parser.TextToMetricFamilies(file)
|
||||||
|
file.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error parsing %q: %v", path, err)
|
||||||
|
error = 1.0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, mf := range parsedFamilies {
|
||||||
|
for _, m := range mf.Metric {
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
log.Errorf("Textfile %q contains unsupported client-side timestamps, skipping entire file", path)
|
||||||
|
error = 1.0
|
||||||
|
continue fileLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mf.Help == nil {
|
||||||
|
help := fmt.Sprintf("Metric read from %s", path)
|
||||||
|
mf.Help = &help
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only set this once it has been parsed and validated, so that
|
||||||
|
// a failure does not appear fresh.
|
||||||
|
mtimes[f.Name()] = f.ModTime()
|
||||||
|
|
||||||
|
for _, mf := range parsedFamilies {
|
||||||
|
convertMetricFamily(mf, ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.exportMTimes(mtimes, ch)
|
||||||
|
|
||||||
|
// Export if there were errors.
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
"wmi_textfile_scrape_error",
|
||||||
|
"1 if there was an error opening or reading a file, 0 otherwise",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
prometheus.GaugeValue, error,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ type WmiCollector struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultCollectors = "cpu,cs,logical_disk,net,os,service,system"
|
defaultCollectors = "cpu,cs,logical_disk,net,os,service,system,textfile"
|
||||||
defaultCollectorsPlaceholder = "[defaults]"
|
defaultCollectorsPlaceholder = "[defaults]"
|
||||||
serviceName = "wmi_exporter"
|
serviceName = "wmi_exporter"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,12 +31,15 @@
|
|||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
<Property Id="TEXTFILE_DIR" Secure="yes"/>
|
||||||
|
<SetProperty Id="TextfileDirFlag" After="InstallFiles" Sequence="execute" Value="--collector.textfile.directory [TEXTFILE_DIR]">TEXTFILE_DIR</SetProperty>
|
||||||
|
|
||||||
<ComponentGroup Id="Files" Directory="APPLICATIONROOTDIRECTORY">
|
<ComponentGroup Id="Files" Directory="APPLICATIONROOTDIRECTORY">
|
||||||
<Component>
|
<Component>
|
||||||
<File Id="wmi_exporter.exe" Name="wmi_exporter.exe" Source="Work\wmi_exporter.exe" KeyPath="yes">
|
<File Id="wmi_exporter.exe" Name="wmi_exporter.exe" Source="Work\wmi_exporter.exe" KeyPath="yes">
|
||||||
<fw:FirewallException Id="MetricsEndpoint" Name="WMI Exporter (HTTP [LISTEN_PORT])" Description="WMI Exporter HTTP endpoint" Port="[LISTEN_PORT]" Protocol="tcp" Scope="any" IgnoreFailure="yes" />
|
<fw:FirewallException Id="MetricsEndpoint" Name="WMI Exporter (HTTP [LISTEN_PORT])" Description="WMI Exporter HTTP endpoint" Port="[LISTEN_PORT]" Protocol="tcp" Scope="any" IgnoreFailure="yes" />
|
||||||
</File>
|
</File>
|
||||||
<ServiceInstall Id="InstallExporterService" Name="wmi_exporter" DisplayName="WMI exporter" Description="Exports Prometheus metrics from WMI queries" ErrorControl="normal" Start="auto" Type="ownProcess" Arguments="--log.format logger:eventlog?name=wmi_exporter [CollectorsFlag] [ListenFlag] [MetricsPathFlag]" />
|
<ServiceInstall Id="InstallExporterService" Name="wmi_exporter" DisplayName="WMI exporter" Description="Exports Prometheus metrics from WMI queries" ErrorControl="normal" Start="auto" Type="ownProcess" Arguments="--log.format logger:eventlog?name=wmi_exporter [CollectorsFlag] [ListenFlag] [MetricsPathFlag] [TextfileDirFlag]" />
|
||||||
<ServiceControl Id="ServiceStateControl" Name="wmi_exporter" Remove="uninstall" Start="install" Stop="both" />
|
<ServiceControl Id="ServiceStateControl" Name="wmi_exporter" Remove="uninstall" Start="install" Stop="both" />
|
||||||
</Component>
|
</Component>
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
@@ -45,4 +48,4 @@
|
|||||||
<ComponentGroupRef Id="Files" />
|
<ComponentGroupRef Id="Files" />
|
||||||
</Feature>
|
</Feature>
|
||||||
</Product>
|
</Product>
|
||||||
</Wix>
|
</Wix>
|
||||||
|
|||||||
Reference in New Issue
Block a user