.. _extensions:
Extensions
==========
Metric-Farmer can be easily extended by developers with own solutions for source and target types.
The reasons for this are the measurement from not yet supported sources (e.g. a department specific Excel list)
or the storage of measurement results on not yet supported targets (e.g. a specific company metric system like
`Prometheus `_)
Concept
-------
Metric-Farmer can be extend by using the `entry-point `_
mechanism of `setuptools `_.
So a Metric-Farmer extension must be a valid Python package, which contains a ``setup.py`` file.
.. code-block:: python
import os
from setuptools import setup
setup(
name='Your extension',
# ... More, but not for us important configurations
entry_points={
'metricfarmer': ['unimportant_name=your_package.your_modul:ExtensionClass']
}
)
During installation of this package, the ``entry_point`` content gets registered on the used Python environment.
For Metric-Farmer the entry-point entry must be a class, which inherits from
``metricfarmer.extensions.MetricFarmerExtension`` and must have common variables, which define sources and target types.
Metric-Farmer creates an instance of this class during startup.
From this point all defined sources and targets types of the extension are available.
A single Python package can register as many Metric-Farmer extensions as it likes.
Step by step introductions
--------------------------
1. Create a new folder ``my_project``
2. Create a ``setup.py`` file and a ``my_mf_extension.py`` inside the above folder.
3. For ``mf_my_extension.py`` use the following content.
.. code-block:: python
from metricfarmer.extensions import MetricFarmerExtension
def my_source_a(**kwargs):
return 100
def my_target_a(metrics, **kwargs):
for metric in metrics.keys():
print metric
class MyExtension(MetricFarmerExtension):
def __init__(self, app):
self.app = app
self.name = "My Extension"
self.namespace = 'me'
self.author = 'Awesome guy'
self.description = 'Metric-Farmer extension...'
self.source_classes = {
'my_source': my_source_a
}
self.target_classes = {
'my_target': my_target_a
}
4. Then register this class inside your ``setup.py`` file:
.. code-block:: python
:emphasize-lines: 14,15
import os
from setuptools import setup, find_packages
setup(
name='My extension project',
version='0.0.1',
license='MIT',
author='Me',
author_email='me@me.com',
description='Collects and stores metrics for my project.',
platforms='any',
packages=find_packages(),
install_requires=['metricfarmer'],
entry_points={
'metricfarmer': ['my_extension=my_project.mf_my_extension:MyExtension']
}
)
5. After that you need to install your package, so that Python is aware of the new entry_point entry:
.. code-block:: bash
pip install -e .
6. Finally you should be able to address your source class with ``me.my_source`` and the target class
with ``me.my_target`` in the related ``class`` parameters of source/target type definitions.
Example
-------
Take a look into the source code of Metric Farmer, as it is using the entry-point mechanism to register all
available sources and targets.
Visit https://github.com/useblocks/metricfarmer/tree/master/metricfarmer/extensions to get an overview about all folders
and files.
The most important stuff is happening in file
`mf_extension.py `_.
There the needed class gets defined.
This class is then used in the `setup.py `_ file as
value for the ``metricfarmer`` entry-point.