openldap-opencensus-stats 0.0.21__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. openldap_opencensus_stats/__init__.py +3 -0
  2. openldap_opencensus_stats/config_transformers/__init__.py +20 -0
  3. openldap_opencensus_stats/config_transformers/base.py +47 -0
  4. openldap_opencensus_stats/config_transformers/child_object.py +75 -0
  5. openldap_opencensus_stats/config_transformers/copy_for_each_database.py +13 -0
  6. openldap_opencensus_stats/config_transformers/metric_dn.py +46 -0
  7. openldap_opencensus_stats/config_transformers/metric_name.py +37 -0
  8. openldap_opencensus_stats/config_transformers/metric_name_interpolation.py +84 -0
  9. openldap_opencensus_stats/config_transformers/metric_query_dn.py +37 -0
  10. openldap_opencensus_stats/config_transformers/snake_case.py +22 -0
  11. openldap_opencensus_stats/configuration.py +172 -0
  12. openldap_opencensus_stats/ldap_metric_set.py +45 -0
  13. openldap_opencensus_stats/ldap_server.py +111 -0
  14. openldap_opencensus_stats/ldap_statistic.py +91 -0
  15. openldap_opencensus_stats/ldap_stats_log_pipe.py +509 -0
  16. openldap_opencensus_stats/ldap_sync_statistic.py +78 -0
  17. openldap_opencensus_stats/main.py +41 -0
  18. openldap_opencensus_stats/sync_metric_set.py +99 -0
  19. openldap_opencensus_stats-0.0.21.data/data/etc/openldap-opencensus-stats.template.yml +125 -0
  20. openldap_opencensus_stats-0.0.21.dist-info/METADATA +431 -0
  21. openldap_opencensus_stats-0.0.21.dist-info/RECORD +24 -0
  22. openldap_opencensus_stats-0.0.21.dist-info/WHEEL +4 -0
  23. openldap_opencensus_stats-0.0.21.dist-info/entry_points.txt +2 -0
  24. openldap_opencensus_stats-0.0.21.dist-info/licenses/LICENSE +661 -0
@@ -0,0 +1,3 @@
1
+ from openldap_opencensus_stats.configuration import Configuration # noqa: F401
2
+ from openldap_opencensus_stats.ldap_server import LdapServer # noqa: F401
3
+ from openldap_opencensus_stats.ldap_statistic import LdapStatistic # noqa: F401
@@ -0,0 +1,20 @@
1
+
2
+ # The transformations process in the order listed here.
3
+ from openldap_opencensus_stats.config_transformers.base \
4
+ import ConfigurationTransformationChainSingleton
5
+ from openldap_opencensus_stats.config_transformers.snake_case \
6
+ import SnakeCaseConfigurationTransformer # noqa: F401
7
+ from openldap_opencensus_stats.config_transformers.metric_dn \
8
+ import MetricDnConfigurationTransformer # noqa: F401
9
+ from openldap_opencensus_stats.config_transformers.copy_for_each_database \
10
+ import CopyForEachDatabaseConfigurationTransformer # noqa: F401
11
+ from openldap_opencensus_stats.config_transformers.child_object \
12
+ import ChildObjectConfigurationTransformer # noqa: F401
13
+ from openldap_opencensus_stats.config_transformers.metric_name_interpolation \
14
+ import MetricNameInterpolationConfigurationTransformer # noqa: F401
15
+ from openldap_opencensus_stats.config_transformers.metric_name \
16
+ import MetricNameConfigurationTransformer # noqa: F401
17
+ from openldap_opencensus_stats.config_transformers.metric_query_dn \
18
+ import MetricQueryDnConfigurationTransformer # noqa: F401
19
+
20
+ ConfigurationTransformationChainSingleton().register(MetricDnConfigurationTransformer)
@@ -0,0 +1,47 @@
1
+ import logging
2
+ import re
3
+
4
+ from openldap_opencensus_stats.ldap_server import LdapServerPool
5
+
6
+
7
+ class ConfigurationTransformer:
8
+ transformers = []
9
+
10
+ def __init_subclass__(cls, **kwargs):
11
+ ConfigurationTransformationChainSingleton().register(cls)
12
+
13
+ @staticmethod
14
+ def process(configuration):
15
+ return configuration
16
+
17
+ @staticmethod
18
+ def get_ldap_server(server_config):
19
+ args = dict([
20
+ (re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower(), value)
21
+ for name, value in server_config.get('connection', {}).items()
22
+ ])
23
+ args['database'] = server_config.get('database')
24
+ ldap_server = LdapServerPool().get_ldap_server(**args)
25
+ return ldap_server
26
+
27
+
28
+ class ConfigurationTransformationChainSingleton:
29
+ transformation_chain = []
30
+
31
+ def __new__(cls, *args, **kwargs):
32
+ if not hasattr(cls, 'instance'):
33
+ cls.instance = super(ConfigurationTransformationChainSingleton, cls).__new__(cls)
34
+ return cls.instance
35
+
36
+ def register(self, cls):
37
+ self.transformation_chain.append(cls)
38
+ logging.info(f"Registered transformer: {cls.__name__}")
39
+
40
+ def transform_configuration(self, configuration):
41
+ configuration_result = {}
42
+ configuration_input = configuration
43
+ for link in self.transformation_chain:
44
+ print(f"Calling configuration chain link {link.__name__}")
45
+ configuration_result = link.process(configuration_input)
46
+ configuration_input = configuration_result
47
+ return configuration_result
@@ -0,0 +1,75 @@
1
+ import copy
2
+ import logging
3
+ import re
4
+
5
+ import ldap
6
+
7
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
8
+
9
+
10
+ class ChildObjectConfigurationTransformer(ConfigurationTransformer):
11
+ @staticmethod
12
+ def process(configuration):
13
+ if not isinstance(configuration, dict):
14
+ raise ValueError('The top level of the configuration must be a mapping.')
15
+
16
+ config = copy.deepcopy(configuration)
17
+ for server_config in config.get('ldap_servers'):
18
+ ldap_server = ChildObjectConfigurationTransformer.get_ldap_server(server_config)
19
+ # A server entry with no object tree defines no cn=Monitor
20
+ # metrics (e.g. statsLogPipe only) and has nothing to transform
21
+ if not server_config.get('sync_only', False) and server_config.get('object'):
22
+ server_config['object'] = ChildObjectConfigurationTransformer.process_objects_for_ldap_server(
23
+ configuration=server_config.get('object'),
24
+ dn='',
25
+ ldap_server=ldap_server
26
+ )
27
+
28
+ return config
29
+
30
+ @staticmethod
31
+ def process_objects_for_ldap_server(configuration, dn, ldap_server):
32
+ if not configuration or not ldap_server:
33
+ raise ValueError(
34
+ 'ChildObjectConfigurationTransformer.process_objects_for_ldap_server: All arguments must exist'
35
+ )
36
+
37
+ if isinstance(configuration, dict):
38
+ config = {}
39
+ for key, value in configuration.items():
40
+ proper_value = ChildObjectConfigurationTransformer.process_objects_for_ldap_server(
41
+ value,
42
+ configuration.get('computed_dn', dn),
43
+ ldap_server
44
+ )
45
+ if key == 'children':
46
+ if not isinstance(proper_value, dict):
47
+ raise TypeError("A configuration entry of 'children' must contain a mapping.")
48
+
49
+ for child_dn in ChildObjectConfigurationTransformer.get_child_keys(dn, ldap_server):
50
+ child_value = copy.deepcopy(proper_value)
51
+ child_value['computed_dn'] = child_dn
52
+ child_value['computed_rdn'] = re.sub(r',.*', '', child_dn)
53
+ new_key = re.sub(r',.*', '', re.sub(r'^[^=]*=', '', child_dn))
54
+ if re.match(child_value.get('rdn'), child_value.get('computed_rdn')):
55
+ config[new_key] = child_value
56
+ else:
57
+ config[key] = proper_value
58
+ return config
59
+ elif isinstance(configuration, list):
60
+ return [
61
+ ChildObjectConfigurationTransformer.process_objects_for_ldap_server(item, dn, ldap_server)
62
+ for item in configuration
63
+ ]
64
+ else:
65
+ return configuration
66
+
67
+ @staticmethod
68
+ def get_child_keys(dn, ldap_server):
69
+ ldap_result = ldap_server.query(dn=dn, scope=ldap.SCOPE_ONELEVEL)
70
+ if not ldap_result:
71
+ logging.warning(f"Found no child objects for {dn} on LDAP database {ldap_server.database}!")
72
+ return [
73
+ result_item[0]
74
+ for result_item in ldap_result
75
+ ]
@@ -0,0 +1,13 @@
1
+ import copy
2
+
3
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
4
+
5
+
6
+ class CopyForEachDatabaseConfigurationTransformer(ConfigurationTransformer):
7
+ @staticmethod
8
+ def process(configuration):
9
+ conf = copy.deepcopy(configuration)
10
+ ldap_servers = conf.get('ldap_servers', [])
11
+ for server_conf in ldap_servers:
12
+ server_conf['object'] = copy.deepcopy(conf.get('object'))
13
+ return conf
@@ -0,0 +1,46 @@
1
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
2
+
3
+
4
+ class MetricDnConfigurationTransformer(ConfigurationTransformer):
5
+ @staticmethod
6
+ def process(configuration):
7
+ return MetricDnConfigurationTransformer.process_object_config(configuration)
8
+
9
+ @staticmethod
10
+ def process_object_config(configuration, suffix_dn='', separator=','):
11
+ if isinstance(configuration, dict):
12
+ config = {}
13
+ if suffix_dn:
14
+ full_suffix = separator + suffix_dn
15
+ else:
16
+ full_suffix = suffix_dn
17
+ computed_dn = suffix_dn
18
+ rdn = configuration.get('computed_rdn', configuration.get('rdn'))
19
+ if rdn:
20
+ computed_dn = rdn + full_suffix
21
+
22
+ for key, value in configuration.items():
23
+ config[key] = MetricDnConfigurationTransformer.process_object_config(
24
+ configuration=value,
25
+ suffix_dn=computed_dn,
26
+ separator=separator
27
+ )
28
+
29
+ # True if either 'rdn' or 'attribute' is a key
30
+ if configuration.get('rdn', configuration.get('attribute')):
31
+ config['computed_dn'] = computed_dn
32
+ else:
33
+ computed_dn = suffix_dn
34
+
35
+ return config
36
+ elif isinstance(configuration, list):
37
+ return [
38
+ MetricDnConfigurationTransformer.process_object_config(
39
+ configuration=item,
40
+ suffix_dn=suffix_dn,
41
+ separator=separator
42
+ )
43
+ for item in configuration
44
+ ]
45
+ else:
46
+ return configuration
@@ -0,0 +1,37 @@
1
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
2
+
3
+
4
+ class MetricNameConfigurationTransformer(ConfigurationTransformer):
5
+ @staticmethod
6
+ def process(configuration):
7
+ return MetricNameConfigurationTransformer.process_object_config(configuration)
8
+
9
+ @staticmethod
10
+ def process_object_config(configuration, prefix='', default_name='', separator='/'):
11
+ full_prefix = prefix + separator if prefix else ''
12
+ if isinstance(configuration, dict):
13
+ config = {}
14
+ metric_name = prefix
15
+ if configuration.get('rdn') or configuration.get('attribute'):
16
+ metric_name = full_prefix + configuration.get('computed_name', configuration.get('name', default_name))
17
+ config['metric_name'] = metric_name
18
+ for key, value in configuration.items():
19
+ config[key] = MetricNameConfigurationTransformer.process_object_config(
20
+ configuration=value,
21
+ prefix=metric_name,
22
+ default_name=key,
23
+ separator=separator
24
+ )
25
+ return config
26
+ elif isinstance(configuration, list):
27
+ return [
28
+ MetricNameConfigurationTransformer.process_object_config(
29
+ configuration=item,
30
+ prefix=prefix,
31
+ default_name=default_name,
32
+ separator=separator
33
+ )
34
+ for item in configuration
35
+ ]
36
+ else:
37
+ return configuration
@@ -0,0 +1,84 @@
1
+ import copy
2
+ import logging
3
+ import re
4
+
5
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
6
+
7
+
8
+ class MetricNameInterpolationConfigurationTransformer(ConfigurationTransformer):
9
+ @staticmethod
10
+ def process(configuration):
11
+ if not isinstance(configuration, dict):
12
+ raise ValueError(
13
+ 'NameInterpolationConfigurationTransformer expect a configuration that is a dict '
14
+ 'but received one that isn\'t.')
15
+
16
+ config = copy.deepcopy(configuration)
17
+ for server_config in config.get('ldap_servers'):
18
+ if not server_config.get('sync_only', False):
19
+ ldap_server = ConfigurationTransformer.get_ldap_server(server_config=server_config)
20
+ server_config['object'] = MetricNameInterpolationConfigurationTransformer.process_objects_for_ldap_server(
21
+ configuration=server_config.get('object', {}),
22
+ dn='',
23
+ ldap_server=ldap_server
24
+ )
25
+ return config
26
+
27
+ @staticmethod
28
+ def process_objects_for_ldap_server(configuration, dn, ldap_server):
29
+
30
+ if isinstance(configuration, list):
31
+ return [
32
+ MetricNameInterpolationConfigurationTransformer.process_objects_for_ldap_server(item, dn, ldap_server)
33
+ for item in configuration
34
+ ]
35
+ elif isinstance(configuration, dict):
36
+ config = {}
37
+
38
+ for key, value in configuration.items():
39
+ proper_value = MetricNameInterpolationConfigurationTransformer.process_objects_for_ldap_server(
40
+ value, dn, ldap_server)
41
+ if key in ['name']:
42
+ config['computed_name'] = MetricNameInterpolationConfigurationTransformer.create_metric_name(
43
+ configuration,
44
+ ldap_server
45
+ )
46
+ config[key] = proper_value
47
+
48
+ return config
49
+
50
+ else:
51
+ return configuration
52
+
53
+ @staticmethod
54
+ def create_metric_name(config, ldap_server):
55
+ def repl_func(matches):
56
+ groups = matches.groups()
57
+ if 'rdn' == groups[0]:
58
+ index = int(groups[1])
59
+ rdn_matches = re.match(
60
+ config.get('rdn'), # Pattern to match - the 'rdn' entry
61
+ config.get('computed_rdn') # String for matching - the 'computed_rdn' entry
62
+ )
63
+ if rdn_matches:
64
+ return rdn_matches.group(index)
65
+ elif 'attr' == groups[0]:
66
+ attribute_name = groups[1]
67
+ ldap_result = ldap_server.query_dn_and_attribute(
68
+ config.get('computed_dn', ''),
69
+ attribute_name
70
+ )
71
+ value = ldap_result[0]
72
+ if isinstance(value, bytes):
73
+ value = value.decode()
74
+ return str(value)
75
+ else:
76
+ logging.error(f"Unknown interpolation requested in name: {groups[0]}.{groups[1]}")
77
+
78
+ name = config.get('computed_name', config.get('name', ''))
79
+ name = re.sub(
80
+ '{([^\\.}]+)\\.([^}]+)}',
81
+ repl_func,
82
+ name
83
+ ).lower()
84
+ return name
@@ -0,0 +1,37 @@
1
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
2
+
3
+
4
+ class MetricQueryDnConfigurationTransformer(ConfigurationTransformer):
5
+ @staticmethod
6
+ def process(configuration):
7
+ return MetricQueryDnConfigurationTransformer.process_object_config(configuration)
8
+
9
+ @staticmethod
10
+ def process_object_config(configuration, query_dn=None):
11
+ if isinstance(configuration, dict):
12
+ config = {}
13
+ configuration_query_dn = configuration.get('query_dn', configuration.get('rdn'))
14
+ if not query_dn and configuration_query_dn:
15
+ query_dn = configuration_query_dn
16
+
17
+ for key, value in configuration.items():
18
+ config[key] = MetricQueryDnConfigurationTransformer.process_object_config(
19
+ configuration=value,
20
+ query_dn=query_dn,
21
+ )
22
+
23
+ # True if either 'rdn' or 'attribute' is a key
24
+ if query_dn:
25
+ config['query_dn'] = query_dn
26
+
27
+ return config
28
+ elif isinstance(configuration, list):
29
+ return [
30
+ MetricQueryDnConfigurationTransformer.process_object_config(
31
+ configuration=item,
32
+ query_dn=query_dn,
33
+ )
34
+ for item in configuration
35
+ ]
36
+ else:
37
+ return configuration
@@ -0,0 +1,22 @@
1
+ import re
2
+
3
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformer
4
+
5
+
6
+ class SnakeCaseConfigurationTransformer(ConfigurationTransformer):
7
+ @staticmethod
8
+ def process(configuration):
9
+ config = {}
10
+ for key, value in configuration.items():
11
+ snake_case_key = re.sub(r'(?<!^)(?=[A-Z])', '_', key).lower()
12
+ if isinstance(value, dict):
13
+ snake_cased_value = SnakeCaseConfigurationTransformer.process(value)
14
+ elif isinstance(value, list):
15
+ snake_cased_value = [
16
+ SnakeCaseConfigurationTransformer.process(x) if isinstance(x, dict) else x
17
+ for x in value
18
+ ]
19
+ else:
20
+ snake_cased_value = value
21
+ config[snake_case_key] = snake_cased_value
22
+ return config
@@ -0,0 +1,172 @@
1
+ import copy
2
+ import logging
3
+ import logging.config
4
+
5
+ import yaml
6
+ from time import sleep
7
+
8
+ from openldap_opencensus_stats.config_transformers.base import ConfigurationTransformationChainSingleton
9
+ from openldap_opencensus_stats.ldap_metric_set import MetricSet
10
+ from openldap_opencensus_stats.sync_metric_set import SyncMetricSet
11
+ from openldap_opencensus_stats.ldap_server import LdapServerPool
12
+ from openldap_opencensus_stats.ldap_statistic import LdapStatistic
13
+ from openldap_opencensus_stats.ldap_stats_log_pipe import LdapStatsLogPipeReader, METRICS_NAMESPACE_DEFAULT
14
+
15
+ from opencensus.stats import stats
16
+ from opencensus.ext.prometheus import stats_exporter
17
+
18
+ # Make up for broken code in the Prometheus exporter
19
+ import opencensus.stats.aggregation_data
20
+ opencensus.stats.aggregation_data.SumAggregationDataFloat = opencensus.stats.aggregation_data.SumAggregationData
21
+
22
+ SUPPORTED_EXPORTERS = ['Prometheus', 'Stackdriver']
23
+
24
+
25
+ class Configuration:
26
+ def __init__(self, config_file_name):
27
+ if config_file_name is None:
28
+ raise ValueError("Config file name must be supplied")
29
+ self._config_file_name = config_file_name
30
+ self._configuration_dict = {}
31
+ self._sleep_time = 5
32
+ self._metric_sets = []
33
+ self._ldap_metrics = {}
34
+ self._stats_log_pipe_readers = []
35
+
36
+ self.reconfigure()
37
+
38
+ def reconfigure(self):
39
+ self._configuration_dict = read_yaml_file(self._config_file_name)
40
+ normalized_configuration = ConfigurationTransformationChainSingleton().transform_configuration(
41
+ self._configuration_dict
42
+ )
43
+
44
+ self._sleep_time = normalized_configuration.get('period', 5)
45
+ log_config = normalized_configuration.get('log_config')
46
+ if log_config and isinstance(log_config, dict):
47
+ log_config['version'] = log_config.get('version', 1)
48
+ logging.config.dictConfig(log_config)
49
+ prometheus_namespace = METRICS_NAMESPACE_DEFAULT
50
+ for exporter_config in normalized_configuration.get('exporters', []):
51
+ exporter = create_exporter(exporter_config)
52
+ stats.stats.view_manager.register_exporter(exporter)
53
+ if exporter_config.get('name') == 'Prometheus':
54
+ prometheus_namespace = exporter.options.namespace
55
+
56
+ for ldap_server_config in normalized_configuration.get('ldap_servers', []):
57
+ if not ldap_server_config.get('sync_only', False):
58
+ metric_set = self.generate_metric_set(ldap_server_config)
59
+ self._metric_sets.append(metric_set)
60
+ stats_log_pipe = ldap_server_config.get('stats_log_pipe')
61
+ if stats_log_pipe:
62
+ if isinstance(stats_log_pipe, str):
63
+ stats_log_pipe = {'pipe': stats_log_pipe}
64
+ stats_log_pipe_reader = LdapStatsLogPipeReader(
65
+ database=ldap_server_config.get('database'),
66
+ pipe_path=stats_log_pipe.get('pipe'),
67
+ suffixes=stats_log_pipe.get('suffixes'),
68
+ namespace=prometheus_namespace
69
+ )
70
+ stats_log_pipe_reader.start()
71
+ self._stats_log_pipe_readers.append(stats_log_pipe_reader)
72
+
73
+ for base_dn, sync_config in normalized_configuration.get('sync', {}).items():
74
+ ldap_server_names = sync_config.get('cluster_servers', [])
75
+ ldap_servers = [
76
+ LdapServerPool().get_ldap_server(**server)
77
+ for server in normalized_configuration.get('ldap_servers', [])
78
+ if server['database'] in ldap_server_names
79
+ ]
80
+ report_servers = sync_config.get('report_servers', [])
81
+ sync_metric_set = SyncMetricSet(
82
+ base_dn=base_dn,
83
+ ldap_servers=ldap_servers,
84
+ report_servers=report_servers
85
+ )
86
+ self._metric_sets.append(sync_metric_set)
87
+
88
+ def generate_metric_set(self, ldap_server_config):
89
+ args = copy.deepcopy(ldap_server_config.get('connection', {}))
90
+ args['database'] = ldap_server_config.get('database')
91
+ ldap_server = LdapServerPool().get_ldap_server(**args)
92
+ metric_set = MetricSet(ldap_server=ldap_server)
93
+ configs = [ldap_server_config.get('object')]
94
+ while configs:
95
+ config = configs.pop()
96
+ if isinstance(config, list):
97
+ for item in config:
98
+ configs.insert(0, item)
99
+ elif isinstance(config, dict):
100
+ dn = config.get('computed_dn')
101
+ name = config.get('metric_name')
102
+ attribute = config.get('attribute')
103
+ unit = config.get('unit')
104
+ description = config.get('description', '')
105
+ value_function = config.get('func', 'value')
106
+ query_dn = config.get('query_dn')
107
+ if dn and name and attribute and unit and query_dn:
108
+ stat = self._ldap_metrics.get(name)
109
+ if not stat:
110
+ stat = LdapStatistic(
111
+ dn=dn,
112
+ name=name,
113
+ attribute=attribute,
114
+ description=description,
115
+ unit=unit,
116
+ value_function=value_function,
117
+ query_dn=query_dn,
118
+ tag_keys=['database']
119
+ )
120
+ self._ldap_metrics[name] = stat
121
+ metric_set.add_statistic(stat)
122
+ for key, value in config.items():
123
+ configs.insert(0, value)
124
+ return metric_set
125
+
126
+ def metric_sets(self):
127
+ return self._metric_sets
128
+
129
+ def sleep(self):
130
+ sleep(self._sleep_time)
131
+
132
+
133
+ def read_yaml_file(file_name):
134
+ with open(file_name, 'r') as file:
135
+ ret_val = yaml.safe_load(file)
136
+ return ret_val
137
+
138
+
139
+ def create_exporter(exporter_configuration=None):
140
+ if exporter_configuration is None:
141
+ raise ValueError("Cannot create an exporter with no configuration!")
142
+
143
+ name = exporter_configuration.get('name')
144
+ if name not in SUPPORTED_EXPORTERS:
145
+ logging.error(
146
+ f"Requested exporter named {name}, which is not supported. Choose from:{', '.join(SUPPORTED_EXPORTERS)}"
147
+ )
148
+ raise ValueError(
149
+ f"Requested exporter named {name}, which is not supported. Choose from:{', '.join(SUPPORTED_EXPORTERS)}"
150
+ )
151
+
152
+ options = exporter_configuration.get('options', {})
153
+ exporter = None
154
+ if "Prometheus" == name:
155
+ if 'options' not in exporter_configuration:
156
+ logging.error("The Prometheus exporter requires options configuration.")
157
+ raise ValueError("The Prometheus exporter requires options configuration.")
158
+ final_options = {'namespace': METRICS_NAMESPACE_DEFAULT, 'port': 8000, 'address': '0.0.0.0'}
159
+ final_options.update(options)
160
+ exporter = stats_exporter.new_stats_exporter(
161
+ stats_exporter.Options(**final_options)
162
+ )
163
+
164
+ elif "Stackdriver" == name:
165
+ # Imported here, not at module level: opencensus-ext-stackdriver and its
166
+ # grpcio dependency are optional (see pyproject.toml's "stackdriver" extra),
167
+ # so this module must not import them unconditionally.
168
+ import opencensus.ext.stackdriver.stats_exporter
169
+ exporter = opencensus.ext.stackdriver.stats_exporter.new_stats_exporter(interval=5)
170
+ print(f"Exporting stats to this project {exporter.options.project_id}")
171
+
172
+ return exporter
@@ -0,0 +1,45 @@
1
+ import copy
2
+
3
+ from opencensus.stats import stats
4
+ from opencensus.tags import tag_map, tag_value, tag_key
5
+
6
+
7
+ class MetricSet:
8
+ def __init__(self, ldap_server=None, ldap_statistics=None):
9
+ self._ldap_server = ldap_server
10
+ if not ldap_statistics or not isinstance(ldap_statistics, list):
11
+ ldap_statistics = []
12
+ self._ldap_statistics = copy.deepcopy(ldap_statistics)
13
+ self._query_dns = set()
14
+
15
+ def set_ldap_server(self, ldap_server):
16
+ self._ldap_server = ldap_server
17
+
18
+ def add_statistic(self, ldap_statistic):
19
+ self._ldap_statistics.append(ldap_statistic)
20
+ self._query_dns.add(ldap_statistic.query_dn)
21
+
22
+ def collect(self):
23
+ tag_keys = [tag_key.TagKey('database')]
24
+ results = {}
25
+ for query_dn in self._query_dns:
26
+ results[query_dn] = dict([
27
+ (result_dn, result_attributes)
28
+ for result_dn, result_attributes in self._ldap_server.query(dn=query_dn)
29
+ ])
30
+ mmap = stats.stats.stats_recorder.new_measurement_map()
31
+ for server_statistic in self._ldap_statistics:
32
+ ldap_value = results.get(
33
+ server_statistic.query_dn, {}
34
+ ).get(
35
+ server_statistic.dn, {}
36
+ ).get(
37
+ server_statistic.attribute
38
+ )
39
+ server_statistic.collect(ldap_server=self._ldap_server, measurement_map=mmap, ldap_value=ldap_value)
40
+ tmap = tag_map.TagMap()
41
+ tmap.insert(
42
+ tag_keys[0],
43
+ tag_value.TagValue(self._ldap_server.database)
44
+ )
45
+ mmap.record(tmap)