Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ default:
fetch_custom_attributes: True
fetch_tags: True
fetch_alarms: True
#exporter_metrics: True
collect_only:
vms: True
vmguests: True
Expand Down Expand Up @@ -113,6 +114,14 @@ limited:
```
Switching sections can be done by adding ?section=limited to the URL.

#### Montitoring the exporter metrics

The exporter exposes metrics about its own behavior as [recommended](https://prometheus.io/docs/instrumenting/writing_clientlibs/#exposition) by Prometheus.

Those metrics are available in the `/metrics` page. By default, those metrics are only exposed in the 'default' section (no need to collect it multiple times). This behavior can be controlled using the `VSPHERE_EXPORTER_METRICS` variable or using `exporter_metrics` in the configuration file.

The metrics about the vmware_exporter process are only available on Linux (see [prometheus/client_python](https://github.com/prometheus/client_python#process-collector)).

#### Environment Variables
| Variable | Precedence | Defaults | Description |
| --------------------------------------| ---------------------- | -------- | --------------------------------------------------------------------------|
Expand All @@ -124,6 +133,7 @@ Switching sections can be done by adding ?section=limited to the URL.
| `VSPHERE_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels |
| `VSPHERE_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels |
| `VSPHERE_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well |
| `VSPHERE_EXPORTER_METRICS` | config, env | True | Set fo false to disable exposing the exporter metric in section default |
| `VSPHERE_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics |
| `VSPHERE_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics |
| `VSPHERE_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics |
Expand All @@ -142,6 +152,7 @@ You can create new sections as well, with very similiar variables. For example,
| `VSPHERE_LIMITED_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels |
| `VSPHERE_LIMITED_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels |
| `VSPHERE_LIMITED_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well |
| `VSPHERE_LIMITED_EXPORTER_METRICS` | config, env | * | Expose exporter metrics ( * Enabled only in section 'default' by default) |
| `VSPHERE_LIMITED_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics |
| `VSPHERE_LIMITED_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics |
| `VSPHERE_LIMITED_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics |
Expand Down
43 changes: 42 additions & 1 deletion tests/unit/test_vmware_exporter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
import datetime
from unittest import mock
from sys import platform

import pytest
import pytest_twisted
Expand Down Expand Up @@ -1525,10 +1526,15 @@ def test_vmware_resource_async_render_GET():
b'vsphere_host': [b'127.0.0.1'],
}

env = {
'VSPHERE_EXPORTER_METRICS': False,
}

args = mock.Mock()
args.config_file = None

resource = VMWareMetricsResource(args)
with mock.patch('vmware_exporter.vmware_exporter.os.environ', env):
resource = VMWareMetricsResource(args)

with mock.patch('vmware_exporter.vmware_exporter.VmwareCollector') as Collector:
Collector.return_value.collect.return_value = []
Expand Down Expand Up @@ -1649,6 +1655,39 @@ def test_vmware_resource_async_render_GET_section():
request.finish.assert_called_with()


@pytest.mark.skipif(platform.startswith("win"), reason="Requires Linux")
@pytest_twisted.inlineCallbacks
def test_vmware_resource_async_render_GET_exportermetrics():
request = mock.Mock()
request.args = {
b'vsphere_host': [b'127.0.0.1'],
}

env = {
'VSPHERE_EXPORTER_METRICS': True,
}

args = mock.Mock()
args.config_file = None

with mock.patch('vmware_exporter.vmware_exporter.os.environ', env):
resource = VMWareMetricsResource(args)

with mock.patch('vmware_exporter.vmware_exporter.VmwareCollector') as Collector:
Collector.return_value.collect.return_value = []
yield resource._async_render_GET(request)

request.setResponseCode.assert_called_with(200)

metrics = []
for s in request.write.call_args[0][0].decode("utf-8").splitlines():
if not s.startswith("#"):
metrics.append(s.split(' ', 1)[0].split('{', 1)[0])

assert 'process_resident_memory_bytes' in metrics
assert 'vmware_exporter_build_info' in metrics


def test_config_env_multiple_sections():
env = {
'VSPHERE_HOST': '127.0.0.10',
Expand Down Expand Up @@ -1680,6 +1719,7 @@ def test_config_env_multiple_sections():
'fetch_custom_attributes': True,
'fetch_tags': True,
'fetch_alarms': True,
'exporter_metrics': True,
'collect_only': {
'datastores': True,
'hosts': True,
Expand All @@ -1697,6 +1737,7 @@ def test_config_env_multiple_sections():
'fetch_custom_attributes': False,
'fetch_tags': False,
'fetch_alarms': False,
'exporter_metrics': False,
'collect_only': {
'datastores': True,
'hosts': True,
Expand Down
27 changes: 24 additions & 3 deletions vmware_exporter/vmware_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@

# Prometheus specific imports
from prometheus_client.core import GaugeMetricFamily
from prometheus_client import CollectorRegistry, generate_latest
from prometheus_client import CollectorRegistry, generate_latest, Gauge
from prometheus_client.core import REGISTRY

from .helpers import batch_fetch_properties, get_bool_env
from .defer import parallelize, run_once_property
from .__init__ import __version__

from .__init__ import __version__

Expand Down Expand Up @@ -1890,6 +1892,7 @@ def configure(self, args):
'fetch_custom_attributes': get_bool_env('VSPHERE_FETCH_CUSTOM_ATTRIBUTES', False),
'fetch_tags': get_bool_env('VSPHERE_FETCH_TAGS', False),
'fetch_alarms': get_bool_env('VSPHERE_FETCH_ALARMS', False),
'exporter_metrics': get_bool_env('VSPHERE_EXPORTER_METRICS', True),
'collect_only': {
'vms': get_bool_env('VSPHERE_COLLECT_VMS', True),
'vmguests': get_bool_env('VSPHERE_COLLECT_VMGUESTS', True),
Expand Down Expand Up @@ -1917,6 +1920,7 @@ def configure(self, args):
'fetch_custom_attributes': get_bool_env('VSPHERE_{}_FETCH_CUSTOM_ATTRIBUTES'.format(section), False),
'fetch_tags': get_bool_env('VSPHERE_{}_FETCH_TAGS'.format(section), False),
'fetch_alarms': get_bool_env('VSPHERE_{}_FETCH_ALARMS'.format(section), False),
'exporter_metrics': get_bool_env('VSPHERE_{}_EXPORTER_METRICS', section.lower() == "default"),
'collect_only': {
'vms': get_bool_env('VSPHERE_{}_COLLECT_VMS'.format(section), True),
'vmguests': get_bool_env('VSPHERE_{}_COLLECT_VMGUESTS'.format(section), True),
Expand Down Expand Up @@ -1953,6 +1957,8 @@ def generate_latest_metrics(self, request):
logging.info("{} is not a valid section, using default".format(section))
section = 'default'

get_exporter_metrics = self.config[section].get('exporter_metrics')

if self.config[section].get('vsphere_host') and self.config[section].get('vsphere_host') != "None":
vsphere_host = self.config[section].get('vsphere_host')
elif request.args.get(b'target', [None])[0]:
Expand All @@ -1979,8 +1985,23 @@ def generate_latest_metrics(self, request):
)
metrics = yield collector.collect()

registry = CollectorRegistry()
registry.register(ListCollector(metrics))
do_metrics_registration = True

if get_exporter_metrics:
registry = REGISTRY
if 'vmware_exporter_build_info' in registry._names_to_collectors:
do_metrics_registration = False
else:
g = Gauge('vmware_exporter_build_info',
'A metric with a constant \'1\' value labeled by version of vmware-exporter.',
["version"], registry=registry)
g.labels(version=__version__)
else:
registry = CollectorRegistry()

if do_metrics_registration:
registry.register(ListCollector(metrics))

output = generate_latest(registry)

request.setHeader("Content-Type", "text/plain; charset=UTF-8")
Expand Down