Sources

A source defines and configures the way a metric shall get measured.

It normally contains a set of parameters, which are shared between all metrics, which use this source. But each metric can override specific parameters for its own measurement.

A metric must reference a source type defined in a .farm-file. And a source type needs to reference a source class, which is provided by Metric-Farmer extensions and defined as a function in a Python file.

Page content

Context example

Image you are working for a company. This company is using Jira for their issue systems. Two different Jira installation exist: One for development tasks and one for product requirements.

The needed functions to access this Jira systems and measure metrics are the same, therefore only one source class is needed, which must be provided by an Metric-Farmer extension.

But both systems are available on different URLs and use different credentials. So two source types are needed, to store the different urls and credentials as parameters. These source types must be configured by the user in a .farm-file.

The needed metrics can then measure the needed JIRA system by referencing the correct source type. The metrics itself are only setting a filter parameter to get the needed data.

@startuml
   hide stereotype
   skinparam defaultTextAlignment center
   skinparam nodeFontColor<<jira_style>> #fff

   node "**Open tasks user A**\n(metric)" as ma #ffcc00
   node "**Open tasks user B**\n(metric)" as mb #ffcc00
   node "**Open requirements user A**\n(metric)" as mc #ffcc00

   node "**Task Jira system**\n(source type)" as ta #abc837
   node "**Requirement Jira system**\n(source type)" as tb #abc837


   node "**Jira**\n(source class)" <<jira_style>> as c #483e37

   ma --> ta
   mb --> ta

   mc --> tb

   ta --> c
   tb --> c

@enduml

Source types

Source types are referenced by metrics and add a use-case specific configuration to a normally not configured source class.

Example: Referenced source in a metric definition

{
  "metrics": {
     "all_html_files": {
        "source": {
          "type": "html_file_count"
        }
     },
     "doc_html_files": {
        "source": {
          "type": "html_file_count",
          "path": "docs/"
        }
     }
  }
}

Both metrics use the same source html_file_count, but the last metric also overrides the path parameter.

Example: Referenced source class in a source definition

{
  "sources": {
    "html_file_count": {
      "class": "mf.file_count",
      "description": "Counts all html files in my project",
      "pattern": "**/*.html"
    }
  }
}

This source references the source class mf.file_count. mf is the namespace of the extension (here Metric-Farmer) and file_count is the source function to call.

Predefined sources

Metric-Farmer provides the predefined sources static, random and file_count. They are used mainly for examples and simple use cases.

This is the content of the .farm-file, which defines the predefined sources:

{
  "sources": {
    "static": {
      "class": "mf.static",
      "description": "Sets a static value for a metric. Default is 0.",
      "value": 0
    },

    "random": {
      "class": "mf.random",
      "description": "Sets a random number between 0 and 10.",
      "min": 0,
      "max": 10,
      "digits": 2
    },

    "file_count": {
      "class": "mf.file_count",
      "description": "Counts all file in the current working directory."
    },

    "rest": {
      "class": "mf.rest",
      "description": "Makes a REST call against a given url."
    }

  }
}

Usage example:

{
  "metrics" : {
    "my_static_metric": {
      "type": "static",
      "value": 42
    },
    "my_random_metric": {
      "type": "random",
      "min": -50,
      "max": 50,
      "digits": 1
    },
    "my_file_count_metric": {
      "type": "file_count",
      "pattern": "**/*.farm"
    }
  }
}

Own sources

Sources get defined in the sources section of a .farm-file.

Example:

{
   "metrics": {}
   "sources": {
      "my_source": {
         "class": "mf.file_count",
         "description": "Counts all c-files in all subfolders"
         "pattern": "**/*.c"
      }
   }
   "targets": {}
}

They must have a class parameter, which must contain a string to reference a source class from a Metric-Farmer extension. Run metricfarmer --list to sell all available source classes.

They should also have a description parameter for documentation.

All other needed parameters are based on the selected source class. So please take a look into their documentation to find out which parameters are available and are mandatory.

Defined sources can be used and referenced in all other .farm-files.

Source classes

A source class is the link to a python function, which does the specific measurement work. They are provided by Metric-Farmer extensions.

For all available source classes on your installation, please execute metricfarmer --list.

Predefined source classes

Metric-Farmer provides already some basic source classes to support some frequent use cases.

You can use them inside your own source type definitions

Each source class has its own set of needed parameters. See their documentation for a detailed picture.

Available target classes are:

mf.static

mf.static allows to get static values from sources.

Parameters
Parameter Description Default Required
value A static value, which is used as result None No

mf.random

mf.random returns a random number as measurement result.

Use min and max parameters to define the range.

Parameters
Parameter Description Default Required
min Minimum value, which is allowed as result 0.0 No
max Maximum value, which is allwoed as result 100.0 No
digits Allowed positions after decimal point 2 No
sleep Seconds to sleep/wait after measurement 0 No

mf.file_count

mf.file_count measure the amount of files inside a folder and its subfolders.

Use pattern to define what kind of files shall get measured.

Parameters
Parameter Description Default Required
path Path to a folder, where Metric-Farmer shall count the files current working directory No
pattern Unix style pattern, which defines what to count. See docs for details. **/* No

mf.rest

mf.rest allows to take a specific part of the answer of a REST call as measurement result.

Parameters
Parameter Description Default Required
url Complete url for the request. None Yes
user Username to use for Basic Authentication, if needed. None No
password Password/Token to use for Basic Authentication, if needed. None No
headers List of headers, which needs to be set for the call. {‘content-type’: ‘application/json’} No
method HTTP method type. Supported are GET, POST and PUT GET No
payload Structured data, which will be send as json data. If method=GET, data must be a flat dictionary. None No
no_escape If True, payload will be added to url unescaped (only GET). False No
result_call Python statement, which gets evaluated and defines the location of the data, which shall be taken as measurement result None No

result_call must be a Python based statement. This statement gets executed and has access to the request result object under the name rest_result.

Imagine the service sends back the following data:

{
   "name": "Frank",
   "age": 32,
   "friends": ["Peter", "Alex", "Sandra"]
}

If the age shall be taken as measurement result, the result_call must be rest_result['age'].

But even more complex measurements are possible. Lets say we need to measure the amount of friends. Then the result_call should be len(rest_result['friends'])).

Example source type

{
   "sources": {
      "company_service": {
         "class": "mf.rest",
         "url": "https://my-company.com/service/api/rest",
         "user": "my-name",
         "password": "my_password",
         "method": "POST",
         "payload": {
            "filter": "Issues = Open"
          },
         "result_call": "result['service_A']['total']"
      }
   }
}

Own source classes

If you wish to create your own source class please take a look into Extensions.