mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-25 14:16:36 +00:00
process: introduce info metric; removed creating_process_id label from all process metric (click here for more information) (#1592)
This commit is contained in:
@@ -37,11 +37,6 @@ Enables IIS process name queries. IIS process names are combined with their app
|
|||||||
|
|
||||||
Disabled by default, and can be enabled with `--collector.process.iis=true`.
|
Disabled by default, and can be enabled with `--collector.process.iis=true`.
|
||||||
|
|
||||||
### `--collector.process.report-owner`
|
|
||||||
|
|
||||||
Enables reporting of the process owner. This is a potentially expensive operation.
|
|
||||||
|
|
||||||
Disabled by default, and can be enabled with `--collector.process.report-owner`.
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
To match all firefox processes: `--collector.process.include="firefox.*"`.
|
To match all firefox processes: `--collector.process.include="firefox.*"`.
|
||||||
@@ -74,23 +69,24 @@ w3wp_Test
|
|||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
| Name | Description | Type | Labels |
|
| Name | Description | Type | Labels |
|
||||||
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|-----------------------------------------------------------------|
|
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------|
|
||||||
| `windows_process_start_time` | Time of process start | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_info` | A metric with a constant '1' value labeled with process information | gauge | `process`, `process_id`, `creating_process_id`, `process_group_id`,`owner`, `cmdline` |
|
||||||
| `windows_process_cpu_time_total` | Returns elapsed time that all of the threads of this process used the processor to execute instructions by mode (privileged, user). An instruction is the basic unit of execution in a computer, a thread is the object that executes instructions, and a process is the object created when a program is run. Code executed to handle some hardware interrupts and trap conditions is included in this count. | counter | `process`, `process_id`, `creating_process_id`, `owner`, `mode` |
|
| `windows_process_start_time` | Time of process start | gauge | `process`, `process_id` |
|
||||||
| `windows_process_handles` | Total number of handles the process has open. This number is the sum of the handles currently open by each thread in the process. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_cpu_time_total` | Returns elapsed time that all of the threads of this process used the processor to execute instructions by mode (privileged, user). An instruction is the basic unit of execution in a computer, a thread is the object that executes instructions, and a process is the object created when a program is run. Code executed to handle some hardware interrupts and trap conditions is included in this count. | counter | `process`, `process_id`, `mode` |
|
||||||
| `windows_process_io_bytes_total` | Bytes issued to I/O operations in different modes (read, write, other). This property counts all I/O activity generated by the process to include file, network, and device I/Os. Read and write mode includes data operations; other mode includes those that do not involve data, such as control operations. | counter | `process`, `process_id`, `creating_process_id`, `owner`, `mode` |
|
| `windows_process_handles` | Total number of handles the process has open. This number is the sum of the handles currently open by each thread in the process. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_io_operations_total` | I/O operations issued in different modes (read, write, other). This property counts all I/O activity generated by the process to include file, network, and device I/Os. Read and write mode includes data operations; other mode includes those that do not involve data, such as control operations. | counter | `process`, `process_id`, `creating_process_id`, `owner`, `mode` |
|
| `windows_process_io_bytes_total` | Bytes issued to I/O operations in different modes (read, write, other). This property counts all I/O activity generated by the process to include file, network, and device I/Os. Read and write mode includes data operations; other mode includes those that do not involve data, such as control operations. | counter | `process`, `process_id`, `mode` |
|
||||||
| `windows_process_page_faults_total` | Page faults by the threads executing in this process. A page fault occurs when a thread refers to a virtual memory page that is not in its working set in main memory. This can cause the page not to be fetched from disk if it is on the standby list and hence already in main memory, or if it is in use by another process with which the page is shared. | counter | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_io_operations_total` | I/O operations issued in different modes (read, write, other). This property counts all I/O activity generated by the process to include file, network, and device I/Os. Read and write mode includes data operations; other mode includes those that do not involve data, such as control operations. | counter | `process`, `process_id`, `mode` |
|
||||||
| `windows_process_page_file_bytes` | Current number of bytes this process has used in the paging file(s). Paging files are used to store pages of memory used by the process that are not contained in other files. Paging files are shared by all processes, and lack of space in paging files can prevent other processes from allocating memory. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_page_faults_total` | Page faults by the threads executing in this process. A page fault occurs when a thread refers to a virtual memory page that is not in its working set in main memory. This can cause the page not to be fetched from disk if it is on the standby list and hence already in main memory, or if it is in use by another process with which the page is shared. | counter | `process`, `process_id` |
|
||||||
| `windows_process_pool_bytes` | Pool Bytes is the last observed number of bytes in the paged or nonpaged pool. The nonpaged pool is an area of system memory (physical memory used by the operating system) for objects that cannot be written to disk, but must remain in physical memory as long as they are allocated. The paged pool is an area of system memory (physical memory used by the operating system) for objects that can be written to disk when they are not being used. Nonpaged pool bytes is calculated differently than paged pool bytes, so it might not equal the total of paged pool bytes. | gauge | `process`, `process_id`, `creating_process_id`, `owner`, `pool` |
|
| `windows_process_page_file_bytes` | Current number of bytes this process has used in the paging file(s). Paging files are used to store pages of memory used by the process that are not contained in other files. Paging files are shared by all processes, and lack of space in paging files can prevent other processes from allocating memory. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_priority_base` | Current base priority of this process. Threads within a process can raise and lower their own base priority relative to the process base priority of the process. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_pool_bytes` | Pool Bytes is the last observed number of bytes in the paged or nonpaged pool. The nonpaged pool is an area of system memory (physical memory used by the operating system) for objects that cannot be written to disk, but must remain in physical memory as long as they are allocated. The paged pool is an area of system memory (physical memory used by the operating system) for objects that can be written to disk when they are not being used. Nonpaged pool bytes is calculated differently than paged pool bytes, so it might not equal the total of paged pool bytes. | gauge | `process`, `process_id`, `pool` |
|
||||||
| `windows_process_private_bytes` | Current number of bytes this process has allocated that cannot be shared with other processes. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_priority_base` | Current base priority of this process. Threads within a process can raise and lower their own base priority relative to the process base priority of the process. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_threads` | Number of threads currently active in this process. An instruction is the basic unit of execution in a processor, and a thread is the object that executes instructions. Every running process has at least one thread. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_private_bytes` | Current number of bytes this process has allocated that cannot be shared with other processes. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_virtual_bytes` | Current size, in bytes, of the virtual address space that the process is using. Use of virtual address space does not necessarily imply corresponding use of either disk or main memory pages. Virtual space is finite and, by using too much, the process can limit its ability to load libraries. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_threads` | Number of threads currently active in this process. An instruction is the basic unit of execution in a processor, and a thread is the object that executes instructions. Every running process has at least one thread. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_working_set_private_bytes` | Size of the working set, in bytes, that is use for this process only and not shared nor shareable by other processes. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_virtual_bytes` | Current size, in bytes, of the virtual address space that the process is using. Use of virtual address space does not necessarily imply corresponding use of either disk or main memory pages. Virtual space is finite and, by using too much, the process can limit its ability to load libraries. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_working_set_peak_bytes` | Maximum size, in bytes, of the Working Set of this process at any point in time. The Working Set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the Working Set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from Working Sets. If they are needed they will then be soft-faulted back into the Working Set before they leave main memory. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_working_set_private_bytes` | Size of the working set, in bytes, that is use for this process only and not shared nor shareable by other processes. | gauge | `process`, `process_id` |
|
||||||
| `windows_process_working_set_bytes` | Maximum number of bytes in the working set of this process at any point in time. The working set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the working set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from working sets. If they are needed, they are then soft-faulted back into the working set before they leave main memory. | gauge | `process`, `process_id`, `creating_process_id`, `owner` |
|
| `windows_process_working_set_peak_bytes` | Maximum size, in bytes, of the Working Set of this process at any point in time. The Working Set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the Working Set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from Working Sets. If they are needed they will then be soft-faulted back into the Working Set before they leave main memory. | gauge | `process`, `process_id` |
|
||||||
|
| `windows_process_working_set_bytes` | Maximum number of bytes in the working set of this process at any point in time. The working set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the working set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from working sets. If they are needed, they are then soft-faulted back into the working set before they leave main memory. | gauge | `process`, `process_id` |
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
@@ -26,14 +27,12 @@ type Config struct {
|
|||||||
ProcessInclude *regexp.Regexp `yaml:"process_include"`
|
ProcessInclude *regexp.Regexp `yaml:"process_include"`
|
||||||
ProcessExclude *regexp.Regexp `yaml:"process_exclude"`
|
ProcessExclude *regexp.Regexp `yaml:"process_exclude"`
|
||||||
EnableWorkerProcess bool `yaml:"enable_iis_worker_process"` //nolint:tagliatelle
|
EnableWorkerProcess bool `yaml:"enable_iis_worker_process"` //nolint:tagliatelle
|
||||||
EnableReportOwner bool `yaml:"enable_report_owner"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConfigDefaults = Config{
|
var ConfigDefaults = Config{
|
||||||
ProcessInclude: types.RegExpAny,
|
ProcessInclude: types.RegExpAny,
|
||||||
ProcessExclude: types.RegExpEmpty,
|
ProcessExclude: types.RegExpEmpty,
|
||||||
EnableWorkerProcess: false,
|
EnableWorkerProcess: false,
|
||||||
EnableReportOwner: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Collector struct {
|
type Collector struct {
|
||||||
@@ -42,6 +41,7 @@ type Collector struct {
|
|||||||
|
|
||||||
lookupCache map[string]string
|
lookupCache map[string]string
|
||||||
|
|
||||||
|
info *prometheus.Desc
|
||||||
cpuTimeTotal *prometheus.Desc
|
cpuTimeTotal *prometheus.Desc
|
||||||
handleCount *prometheus.Desc
|
handleCount *prometheus.Desc
|
||||||
ioBytesTotal *prometheus.Desc
|
ioBytesTotal *prometheus.Desc
|
||||||
@@ -101,11 +101,6 @@ func NewWithFlags(app *kingpin.Application) *Collector {
|
|||||||
"Enable IIS worker process name queries. May cause the collector to leak memory.",
|
"Enable IIS worker process name queries. May cause the collector to leak memory.",
|
||||||
).Default(strconv.FormatBool(c.config.EnableWorkerProcess)).BoolVar(&c.config.EnableWorkerProcess)
|
).Default(strconv.FormatBool(c.config.EnableWorkerProcess)).BoolVar(&c.config.EnableWorkerProcess)
|
||||||
|
|
||||||
app.Flag(
|
|
||||||
"collector.process.report-owner",
|
|
||||||
"Enable reporting of process owner.",
|
|
||||||
).Default(strconv.FormatBool(c.config.EnableReportOwner)).BoolVar(&c.config.EnableReportOwner)
|
|
||||||
|
|
||||||
app.Action(func(*kingpin.ParseContext) error {
|
app.Action(func(*kingpin.ParseContext) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -150,99 +145,101 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
_ = level.Warn(logger).Log("msg", "No filters specified for process collector. This will generate a very large number of metrics!")
|
_ = level.Warn(logger).Log("msg", "No filters specified for process collector. This will generate a very large number of metrics!")
|
||||||
}
|
}
|
||||||
|
|
||||||
commonLabels := make([]string, 0)
|
c.info = prometheus.NewDesc(
|
||||||
if c.config.EnableReportOwner {
|
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
||||||
commonLabels = []string{"owner"}
|
"Process information.",
|
||||||
}
|
[]string{"process", "process_id", "creating_process_id", "process_group_id", "owner", "cmdline"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
c.startTime = prometheus.NewDesc(
|
c.startTime = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "start_time"),
|
prometheus.BuildFQName(types.Namespace, Name, "start_time"),
|
||||||
"Time of process start.",
|
"Time of process start.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.cpuTimeTotal = prometheus.NewDesc(
|
c.cpuTimeTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "cpu_time_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "cpu_time_total"),
|
||||||
"Returns elapsed time that all of the threads of this process used the processor to execute instructions by mode (privileged, user).",
|
"Returns elapsed time that all of the threads of this process used the processor to execute instructions by mode (privileged, user).",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id", "mode"),
|
[]string{"process", "process_id", "mode"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.handleCount = prometheus.NewDesc(
|
c.handleCount = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "handles"),
|
prometheus.BuildFQName(types.Namespace, Name, "handles"),
|
||||||
"Total number of handles the process has open. This number is the sum of the handles currently open by each thread in the process.",
|
"Total number of handles the process has open. This number is the sum of the handles currently open by each thread in the process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.ioBytesTotal = prometheus.NewDesc(
|
c.ioBytesTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "io_bytes_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "io_bytes_total"),
|
||||||
"Bytes issued to I/O operations in different modes (read, write, other).",
|
"Bytes issued to I/O operations in different modes (read, write, other).",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id", "mode"),
|
[]string{"process", "process_id", "mode"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.ioOperationsTotal = prometheus.NewDesc(
|
c.ioOperationsTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "io_operations_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "io_operations_total"),
|
||||||
"I/O operations issued in different modes (read, write, other).",
|
"I/O operations issued in different modes (read, write, other).",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id", "mode"),
|
[]string{"process", "process_id", "mode"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.pageFaultsTotal = prometheus.NewDesc(
|
c.pageFaultsTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "page_faults_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "page_faults_total"),
|
||||||
"Page faults by the threads executing in this process.",
|
"Page faults by the threads executing in this process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.pageFileBytes = prometheus.NewDesc(
|
c.pageFileBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "page_file_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "page_file_bytes"),
|
||||||
"Current number of bytes this process has used in the paging file(s).",
|
"Current number of bytes this process has used in the paging file(s).",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.poolBytes = prometheus.NewDesc(
|
c.poolBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "pool_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "pool_bytes"),
|
||||||
"Pool Bytes is the last observed number of bytes in the paged or nonpaged pool.",
|
"Pool Bytes is the last observed number of bytes in the paged or nonpaged pool.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id", "pool"),
|
[]string{"process", "process_id", "pool"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.priorityBase = prometheus.NewDesc(
|
c.priorityBase = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "priority_base"),
|
prometheus.BuildFQName(types.Namespace, Name, "priority_base"),
|
||||||
"Current base priority of this process. Threads within a process can raise and lower their own base priority relative to the process base priority of the process.",
|
"Current base priority of this process. Threads within a process can raise and lower their own base priority relative to the process base priority of the process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.privateBytes = prometheus.NewDesc(
|
c.privateBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "private_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "private_bytes"),
|
||||||
"Current number of bytes this process has allocated that cannot be shared with other processes.",
|
"Current number of bytes this process has allocated that cannot be shared with other processes.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.threadCount = prometheus.NewDesc(
|
c.threadCount = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "threads"),
|
prometheus.BuildFQName(types.Namespace, Name, "threads"),
|
||||||
"Number of threads currently active in this process.",
|
"Number of threads currently active in this process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.virtualBytes = prometheus.NewDesc(
|
c.virtualBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "virtual_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "virtual_bytes"),
|
||||||
"Current size, in bytes, of the virtual address space that the process is using.",
|
"Current size, in bytes, of the virtual address space that the process is using.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.workingSetPrivate = prometheus.NewDesc(
|
c.workingSetPrivate = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "working_set_private_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "working_set_private_bytes"),
|
||||||
"Size of the working set, in bytes, that is use for this process only and not shared nor shareable by other processes.",
|
"Size of the working set, in bytes, that is use for this process only and not shared nor shareable by other processes.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.workingSetPeak = prometheus.NewDesc(
|
c.workingSetPeak = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "working_set_peak_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "working_set_peak_bytes"),
|
||||||
"Maximum size, in bytes, of the Working Set of this process at any point in time. The Working Set is the set of memory pages touched recently by the threads in the process.",
|
"Maximum size, in bytes, of the Working Set of this process at any point in time. The Working Set is the set of memory pages touched recently by the threads in the process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.workingSet = prometheus.NewDesc(
|
c.workingSet = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "working_set_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "working_set_bytes"),
|
||||||
"Maximum number of bytes in the working set of this process at any point in time. The working set is the set of memory pages touched recently by the threads in the process.",
|
"Maximum number of bytes in the working set of this process at any point in time. The working set is the set of memory pages touched recently by the threads in the process.",
|
||||||
append(commonLabels, "process", "process_id", "creating_process_id"),
|
[]string{"process", "process_id"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -303,8 +300,6 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var owner string
|
|
||||||
|
|
||||||
for _, process := range data {
|
for _, process := range data {
|
||||||
if process.Name == "_Total" ||
|
if process.Name == "_Total" ||
|
||||||
c.config.ProcessExclude.MatchString(process.Name) ||
|
c.config.ProcessExclude.MatchString(process.Name) ||
|
||||||
@@ -326,164 +321,163 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := make([]string, 0, 4)
|
cmdLine, processOwner, processGroupID, err := c.getProcessInformation(logger, uint32(process.IDProcess))
|
||||||
|
if err != nil {
|
||||||
if c.config.EnableReportOwner {
|
_ = level.Debug(logger).Log("msg", "Failed to get process information", "pid", pid, "err", err)
|
||||||
owner, err = c.getProcessOwner(int(process.IDProcess))
|
|
||||||
if err != nil {
|
|
||||||
owner = "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
labels = []string{owner}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
labels = append(labels, processName, pid, parentPID)
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.info,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
processName, pid, parentPID, strconv.Itoa(int(processGroupID)), processOwner, cmdLine,
|
||||||
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.startTime,
|
c.startTime,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.ElapsedTime,
|
process.ElapsedTime,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.handleCount,
|
c.handleCount,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.HandleCount,
|
process.HandleCount,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.cpuTimeTotal,
|
c.cpuTimeTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.PercentPrivilegedTime,
|
process.PercentPrivilegedTime,
|
||||||
append(labels, "privileged")...,
|
processName, pid, "privileged",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.cpuTimeTotal,
|
c.cpuTimeTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.PercentUserTime,
|
process.PercentUserTime,
|
||||||
append(labels, "user")...,
|
processName, pid, "user",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioBytesTotal,
|
c.ioBytesTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOOtherBytesPerSec,
|
process.IOOtherBytesPerSec,
|
||||||
append(labels, "other")...,
|
processName, pid, "other",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioOperationsTotal,
|
c.ioOperationsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOOtherOperationsPerSec,
|
process.IOOtherOperationsPerSec,
|
||||||
append(labels, "other")...,
|
processName, pid, "other",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioBytesTotal,
|
c.ioBytesTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOReadBytesPerSec,
|
process.IOReadBytesPerSec,
|
||||||
append(labels, "read")...,
|
processName, pid, "read",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioOperationsTotal,
|
c.ioOperationsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOReadOperationsPerSec,
|
process.IOReadOperationsPerSec,
|
||||||
append(labels, "read")...,
|
processName, pid, "read",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioBytesTotal,
|
c.ioBytesTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOWriteBytesPerSec,
|
process.IOWriteBytesPerSec,
|
||||||
append(labels, "write")...,
|
processName, pid, "write",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ioOperationsTotal,
|
c.ioOperationsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.IOWriteOperationsPerSec,
|
process.IOWriteOperationsPerSec,
|
||||||
append(labels, "write")...,
|
processName, pid, "write",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.pageFaultsTotal,
|
c.pageFaultsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
process.PageFaultsPerSec,
|
process.PageFaultsPerSec,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.pageFileBytes,
|
c.pageFileBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.PageFileBytes,
|
process.PageFileBytes,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.poolBytes,
|
c.poolBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.PoolNonPagedBytes,
|
process.PoolNonPagedBytes,
|
||||||
append(labels, "nonpaged")...,
|
processName, pid, "nonpaged",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.poolBytes,
|
c.poolBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.PoolPagedBytes,
|
process.PoolPagedBytes,
|
||||||
append(labels, "paged")...,
|
processName, pid, "paged",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.priorityBase,
|
c.priorityBase,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.PriorityBase,
|
process.PriorityBase,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.privateBytes,
|
c.privateBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.PrivateBytes,
|
process.PrivateBytes,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.threadCount,
|
c.threadCount,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.ThreadCount,
|
process.ThreadCount,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.virtualBytes,
|
c.virtualBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.VirtualBytes,
|
process.VirtualBytes,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.workingSetPrivate,
|
c.workingSetPrivate,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.WorkingSetPrivate,
|
process.WorkingSetPrivate,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.workingSetPeak,
|
c.workingSetPeak,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.WorkingSetPeak,
|
process.WorkingSetPeak,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.workingSet,
|
c.workingSet,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
process.WorkingSet,
|
process.WorkingSet,
|
||||||
labels...,
|
processName, pid,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,39 +485,137 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ref: https://github.com/microsoft/hcsshim/blob/8beabacfc2d21767a07c20f8dd5f9f3932dbf305/internal/uvm/stats.go#L25
|
// ref: https://github.com/microsoft/hcsshim/blob/8beabacfc2d21767a07c20f8dd5f9f3932dbf305/internal/uvm/stats.go#L25
|
||||||
func (c *Collector) getProcessOwner(pid int) (string, error) {
|
func (c *Collector) getProcessInformation(logger log.Logger, pid uint32) (string, string, uint32, error) {
|
||||||
p, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
|
hProcess, vmReadAccess, err := c.openProcess(pid)
|
||||||
if errors.Is(err, syscall.Errno(0x57)) { // invalid parameter, for PIDs that don't exist
|
|
||||||
return "", errors.New("process not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("OpenProcess: %w", err)
|
return "", "", 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer windows.Close(p)
|
defer func(hProcess windows.Handle) {
|
||||||
|
if err := windows.CloseHandle(hProcess); err != nil {
|
||||||
|
_ = level.Warn(logger).Log("msg", "CloseHandle failed", "err", err)
|
||||||
|
}
|
||||||
|
}(hProcess)
|
||||||
|
|
||||||
|
owner, err := c.getProcessOwner(logger, hProcess)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
cmdLine string
|
||||||
|
processGroupID uint32
|
||||||
|
)
|
||||||
|
|
||||||
|
if vmReadAccess {
|
||||||
|
cmdLine, processGroupID, err = c.getExtendedProcessInformation(hProcess)
|
||||||
|
if err != nil {
|
||||||
|
return "", owner, processGroupID, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdLine, owner, processGroupID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) getExtendedProcessInformation(hProcess windows.Handle) (string, uint32, error) {
|
||||||
|
// Get the process environment block (PEB) address
|
||||||
|
var pbi windows.PROCESS_BASIC_INFORMATION
|
||||||
|
retLen := uint32(unsafe.Sizeof(pbi))
|
||||||
|
if err := windows.NtQueryInformationProcess(hProcess, windows.ProcessBasicInformation, unsafe.Pointer(&pbi), retLen, &retLen); err != nil {
|
||||||
|
return "", 0, fmt.Errorf("failed to query process basic information: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peb := windows.PEB{}
|
||||||
|
err := windows.ReadProcessMemory(hProcess,
|
||||||
|
uintptr(unsafe.Pointer(pbi.PebBaseAddress)),
|
||||||
|
(*byte)(unsafe.Pointer(&peb)),
|
||||||
|
unsafe.Sizeof(peb),
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, fmt.Errorf("failed to read process memory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
processParameters := windows.RTL_USER_PROCESS_PARAMETERS{}
|
||||||
|
err = windows.ReadProcessMemory(hProcess,
|
||||||
|
uintptr(unsafe.Pointer(peb.ProcessParameters)),
|
||||||
|
(*byte)(unsafe.Pointer(&processParameters)),
|
||||||
|
unsafe.Sizeof(processParameters),
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, fmt.Errorf("failed to read process memory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdLineUTF16 := make([]uint16, processParameters.CommandLine.Length)
|
||||||
|
|
||||||
|
err = windows.ReadProcessMemory(hProcess,
|
||||||
|
uintptr(unsafe.Pointer(processParameters.CommandLine.Buffer)),
|
||||||
|
(*byte)(unsafe.Pointer(&cmdLineUTF16[0])),
|
||||||
|
uintptr(processParameters.CommandLine.Length),
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", processParameters.ProcessGroupId, fmt.Errorf("failed to read process memory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(windows.UTF16ToString(cmdLineUTF16)), processParameters.ProcessGroupId, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) getProcessOwner(logger log.Logger, hProcess windows.Handle) (string, error) {
|
||||||
var tok windows.Token
|
var tok windows.Token
|
||||||
if err = windows.OpenProcessToken(p, windows.TOKEN_QUERY, &tok); err != nil {
|
|
||||||
return "", fmt.Errorf("OpenProcessToken: %w", err)
|
if err := windows.OpenProcessToken(hProcess, windows.TOKEN_QUERY, &tok); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to open process token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func(tok windows.Token) {
|
||||||
|
if err := tok.Close(); err != nil {
|
||||||
|
_ = level.Warn(logger).Log("msg", "Token close failed", "err", err)
|
||||||
|
}
|
||||||
|
}(tok)
|
||||||
|
|
||||||
tokenUser, err := tok.GetTokenUser()
|
tokenUser, err := tok.GetTokenUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("GetTokenUser: %w", err)
|
return "", fmt.Errorf("failed to get token user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sid := tokenUser.User.Sid.String()
|
sid := tokenUser.User.Sid.String()
|
||||||
if owner, ok := c.lookupCache[sid]; ok {
|
|
||||||
return owner, nil
|
owner, ok := c.lookupCache[sid]
|
||||||
|
if !ok {
|
||||||
|
account, domain, _, err := tokenUser.User.Sid.LookupAccount("")
|
||||||
|
if err != nil {
|
||||||
|
owner = sid
|
||||||
|
} else {
|
||||||
|
owner = fmt.Sprintf(`%s\%s`, account, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.lookupCache[sid] = owner
|
||||||
}
|
}
|
||||||
|
|
||||||
account, domain, _, err := tokenUser.User.Sid.LookupAccount("")
|
return owner, nil
|
||||||
if err != nil {
|
}
|
||||||
c.lookupCache[sid] = sid
|
|
||||||
} else {
|
func (c *Collector) openProcess(pid uint32) (windows.Handle, bool, error) {
|
||||||
c.lookupCache[sid] = fmt.Sprintf(`%s\%s`, account, domain)
|
// Open the process with QUERY_INFORMATION and VM_READ permissions
|
||||||
}
|
hProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, pid)
|
||||||
|
if err == nil {
|
||||||
return c.lookupCache[sid], nil
|
return hProcess, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.Is(err, windows.ERROR_ACCESS_DENIED) {
|
||||||
|
return 0, false, fmt.Errorf("failed to open process: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.Is(err, syscall.Errno(0x57)) { // invalid parameter, for PIDs that don't exist
|
||||||
|
return 0, false, errors.New("process not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
hProcess, err = windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false, fmt.Errorf("failed to open process with limited permissions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hProcess, false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ windows_exporter_collector_success{collector="logical_disk"} 1
|
|||||||
windows_exporter_collector_success{collector="physical_disk"} 1
|
windows_exporter_collector_success{collector="physical_disk"} 1
|
||||||
windows_exporter_collector_success{collector="net"} 1
|
windows_exporter_collector_success{collector="net"} 1
|
||||||
windows_exporter_collector_success{collector="os"} 1
|
windows_exporter_collector_success{collector="os"} 1
|
||||||
|
windows_exporter_collector_success{collector="process"} 1
|
||||||
windows_exporter_collector_success{collector="scheduled_task"} 1
|
windows_exporter_collector_success{collector="scheduled_task"} 1
|
||||||
windows_exporter_collector_success{collector="service"} 1
|
windows_exporter_collector_success{collector="service"} 1
|
||||||
windows_exporter_collector_success{collector="system"} 1
|
windows_exporter_collector_success{collector="system"} 1
|
||||||
@@ -55,6 +56,7 @@ windows_exporter_collector_timeout{collector="logical_disk"} 0
|
|||||||
windows_exporter_collector_timeout{collector="physical_disk"} 0
|
windows_exporter_collector_timeout{collector="physical_disk"} 0
|
||||||
windows_exporter_collector_timeout{collector="net"} 0
|
windows_exporter_collector_timeout{collector="net"} 0
|
||||||
windows_exporter_collector_timeout{collector="os"} 0
|
windows_exporter_collector_timeout{collector="os"} 0
|
||||||
|
windows_exporter_collector_timeout{collector="process"} 0
|
||||||
windows_exporter_collector_timeout{collector="scheduled_task"} 0
|
windows_exporter_collector_timeout{collector="scheduled_task"} 0
|
||||||
windows_exporter_collector_timeout{collector="service"} 0
|
windows_exporter_collector_timeout{collector="service"} 0
|
||||||
windows_exporter_collector_timeout{collector="system"} 0
|
windows_exporter_collector_timeout{collector="system"} 0
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ mkdir $textfile_dir | Out-Null
|
|||||||
Copy-Item 'e2e-textfile.prom' -Destination "$($textfile_dir)/e2e-textfile.prom"
|
Copy-Item 'e2e-textfile.prom' -Destination "$($textfile_dir)/e2e-textfile.prom"
|
||||||
|
|
||||||
# Omit dynamic collector information that will change after each run
|
# Omit dynamic collector information that will change after each run
|
||||||
$skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_logical_disk|windows_physical_disk|windows_net|windows_os|windows_service|windows_system|windows_textfile_mtime_seconds)"
|
$skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_logical_disk|windows_physical_disk|windows_net|windows_os|windows_process|windows_service|windows_system|windows_textfile_mtime_seconds)"
|
||||||
|
|
||||||
# Start process in background, awaiting HTTP requests.
|
# Start process in background, awaiting HTTP requests.
|
||||||
# Use default collectors, port and address: http://localhost:9182/metrics
|
# Use default collectors, port and address: http://localhost:9182/metrics
|
||||||
$exporter_proc = Start-Process `
|
$exporter_proc = Start-Process `
|
||||||
-PassThru `
|
-PassThru `
|
||||||
-FilePath ..\windows_exporter.exe `
|
-FilePath ..\windows_exporter.exe `
|
||||||
-ArgumentList "--log.level=debug --web.disable-exporter-metrics --collectors.enabled=[defaults],textfile,scheduled_task --collector.scheduled_task.include=.*WinSAT --collector.textfile.directories=$($textfile_dir)" `
|
-ArgumentList "--log.level=debug --web.disable-exporter-metrics --collectors.enabled=[defaults],textfile,process,scheduled_task --collector.process.include=explorer.exe --collector.scheduled_task.include=.*WinSAT --collector.textfile.directories=$($textfile_dir)" `
|
||||||
-WindowStyle Hidden `
|
-WindowStyle Hidden `
|
||||||
-RedirectStandardOutput "$($temp_dir)/windows_exporter.log" `
|
-RedirectStandardOutput "$($temp_dir)/windows_exporter.log" `
|
||||||
-RedirectStandardError "$($temp_dir)/windows_exporter_error.log"
|
-RedirectStandardError "$($temp_dir)/windows_exporter_error.log"
|
||||||
|
|||||||
Reference in New Issue
Block a user