-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flexible Dimension #46
base: master
Are you sure you want to change the base?
Changes from all commits
8803422
3efaf11
ca2f6aa
d5985b1
a8d6246
6f99f7e
6a596c6
a76fba8
8f575f8
e5a2cf9
439a0be
0379ec4
727c836
64c165d
2f77f00
defdc0b
5644fec
c4a2519
c2f3b5b
4b20aba
c2ab580
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
InstanceId | ||
PluginInstance |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from ..logger.logger import get_logger | ||
|
||
class DimensionConfigReader(object): | ||
""" | ||
The DimensionConfigReader is responsible for parsing the dimension.conf file into a dimension list | ||
used by the Dimension class. | ||
""" | ||
_LOGGER = get_logger(__name__) | ||
|
||
def __init__(self, dimension_config_path): | ||
self.dimension_config_path = dimension_config_path | ||
|
||
def get_dimension_list(self): | ||
""" | ||
Reads dimension configuration file and returns a list of dimension name. | ||
:return: dimension list configured | ||
""" | ||
try: | ||
return self._get_dimensions_from_file(self.dimension_config_path) | ||
except IOError as e: | ||
self._LOGGER.warning("Could not open dimension file '" + self.dimension_config_path + "'. Reason: " + str(e)) | ||
return None | ||
|
||
def _get_dimensions_from_file(self, dimension_path): | ||
dimensions = [] | ||
with open(dimension_path) as dimension_file: | ||
lines = dimension_file.readlines() | ||
for line in lines: | ||
dimensions.append(line.rstrip()) | ||
return dimensions | ||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from logger.logger import get_logger | ||
from dimensionplugins import * | ||
from configuration.dimensionreader import DimensionConfigReader | ||
|
||
class Dimensions(object): | ||
""" | ||
The Dimensions is responsible for holding all dimension plugins | ||
""" | ||
_LOGGER = get_logger(__name__) | ||
|
||
def __init__(self, config_helper, vl): | ||
self.config = config_helper | ||
self.vl = vl | ||
self.dimension_handlers = dict() | ||
self.dimension_handlers["InstanceId"] = Dimension_InstanceId(self.config, self.vl) | ||
self.dimension_handlers["PluginInstance"] = Dimension_PluginInstance(self.config, self.vl) | ||
self.dimension_handlers["Hostname"] = Dimension_Hostname(self.config, self.vl) | ||
for h in self.dimension_handlers: | ||
self.dimension_handlers[h].register_plugin() | ||
|
||
""" | ||
Go through the configured dimension list and find out if there is a plugin can handle it | ||
""" | ||
def get_dimensions(self): | ||
dimension_config_list = DimensionConfigReader(self.config.DIMENSION_CONFIG_PATH).get_dimension_list() | ||
dimensions = dict() | ||
for dm in dimension_config_list: | ||
if dm in self.dimension_handlers: | ||
self.dimension_handlers[dm].func(dimensions, self.dimension_handlers[dm].args) | ||
return dimensions | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
""" | ||
This Dimension Plugin abstract base class file | ||
""" | ||
|
||
class DimensionPlugin(object): | ||
""" | ||
Base class of Dimension plugin. | ||
Any vendor can implement a derived class | ||
""" | ||
def __init__(self, config_helper, vl): | ||
self.func = None | ||
self.args = None | ||
self.config = config_helper | ||
self.vl = vl | ||
|
||
def __str__(self): | ||
if self.func and self.args: | ||
return "func: %s, args: %s" % (self.func.__name__, self.args) | ||
else: | ||
return __name__ | ||
|
||
""" | ||
Abstract method: register dimension plugin function | ||
""" | ||
def register_plugin(self): | ||
pass | ||
|
||
from generic_dimensions import * | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
""" | ||
This is the file containing generic dimension plugin classes | ||
""" | ||
|
||
import os | ||
from . import DimensionPlugin | ||
|
||
""" | ||
This InstanceId Dimension coming from configured host instance | ||
""" | ||
|
||
def dimension_get_instance_id(dimension, args): | ||
dimension[args['name']] = args['value'] | ||
|
||
class Dimension_InstanceId(DimensionPlugin): | ||
def register_plugin(self): | ||
self.func = dimension_get_instance_id | ||
self.args = { | ||
'name': "InstanceId", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like the name of this dimension was "Host", now it is changed to "InstanceId", do not know if it will bring confusion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This flexible dimension is configurable. We definitely can implement another Dimension_Host class with the same code. It is up to us and the user to expand the scenarios. Here, I am just giving two examples. I will write more document to explain how to use this feature. |
||
'value': self.config.host | ||
} | ||
|
||
|
||
""" | ||
This PluginInstance Dimension coming from collectd value plugin instance | ||
""" | ||
|
||
def dimension_get_plugin_instance(dimension, args): | ||
dimension[args['name']] = args['value'] | ||
|
||
class Dimension_PluginInstance(DimensionPlugin): | ||
def register_plugin(self): | ||
self.func = dimension_get_plugin_instance | ||
plugin_instance = self.vl.plugin_instance if self.vl.plugin_instance else "NONE" | ||
self.args = { | ||
'name': "PluginInstance", | ||
'value': plugin_instance | ||
} | ||
|
||
|
||
""" | ||
Hostname Dimension report the hostname value | ||
""" | ||
|
||
def dimension_get_hostname(dimension, args): | ||
dimension[args['name']] = args['value'] | ||
|
||
class Dimension_Hostname(DimensionPlugin): | ||
def register_plugin(self): | ||
self.func = dimension_get_hostname | ||
self.args = { | ||
'name': "Hostname", | ||
'value': os.uname()[1] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not know if following issue will happen. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
import awsutils as awsutils | ||
import plugininfo | ||
import datetime | ||
from logger.logger import get_logger | ||
from dimensionhandler import Dimensions | ||
|
||
class MetricDataStatistic(object): | ||
""" | ||
|
@@ -86,11 +88,11 @@ def __init__(self, config_helper, vl, adjusted_time=None): | |
|
||
def build(self): | ||
""" Builds metric data object with name and dimensions but without value or statistics """ | ||
metric_array = [MetricDataStatistic(metric_name=self._build_metric_name(), dimensions=self._build_metric_dimensions(), timestamp=self._build_timestamp())] | ||
metric_array = [MetricDataStatistic(metric_name=self._build_metric_name(), unit=self.vl.type_instance, dimensions=self._build_metric_dimensions(), timestamp=self._build_timestamp())] | ||
if self.config.push_asg: | ||
metric_array.append(MetricDataStatistic(metric_name=self._build_metric_name(), dimensions=self._build_asg_dimension(), timestamp=self._build_timestamp())) | ||
metric_array.append(MetricDataStatistic(metric_name=self._build_metric_name(), unit=self.vl.type_instance, dimensions=self._build_asg_dimension(), timestamp=self._build_timestamp())) | ||
if self.config.push_constant: | ||
metric_array.append(MetricDataStatistic(metric_name=self._build_metric_name(), dimensions=self._build_constant_dimension(), timestamp=self._build_timestamp())) | ||
metric_array.append(MetricDataStatistic(metric_name=self._build_metric_name(), unit=self.vl.type_instance, dimensions=self._build_constant_dimension(), timestamp=self._build_timestamp())) | ||
return metric_array | ||
|
||
def _build_timestamp(self): | ||
|
@@ -123,10 +125,14 @@ def _build_constant_dimension(self): | |
return dimensions | ||
|
||
def _build_metric_dimensions(self): | ||
dimensions = { | ||
"Host" : self._get_host_dimension(), | ||
"PluginInstance" : self._get_plugin_instance_dimension() | ||
} | ||
if self.config.DIMENSION_CONFIG_PATH != None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use "if self.config.DIMENSION_CONFIG_PATH:" If the configuration file is empty. how to handle it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the configuration file is empty, it will fall into the else case, which will use the original implementation to use the fixed dimension of "Host" and "PluginInstance". |
||
d = Dimensions(self.config, self.vl) | ||
dimensions = d.get_dimensions() | ||
else: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a ASG feature pushed, it added a fixed dimension, maybe it will have some conflict with this pull request. Could you merge it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I am going to merge it in my new merge request. |
||
dimensions = { | ||
"Host" : self._get_host_dimension(), | ||
"PluginInstance" : self._get_plugin_instance_dimension() | ||
} | ||
if self.config.push_asg: | ||
dimensions["AutoScalingGroup"] = self._get_autoscaling_group() | ||
if self.config.push_constant: | ||
|
@@ -147,3 +153,4 @@ def _get_autoscaling_group(self): | |
if self.config.asg_name: | ||
return self.config.asg_name | ||
return "NONE" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
InstanceId | ||
PluginInstance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that collectd give different unit every time? for example: sometimes, it is seconds, some times, it is miscroseconds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is possible according to collectd protocol. We implemented that in our collectd read plugin.