Skip to content
Snippets Groups Projects
Commit 06c625ad authored by PICHOU Kyâne's avatar PICHOU Kyâne
Browse files

Add Mattermost module

parent 1104f522
No related branches found
No related tags found
1 merge request!1Merge dev
......@@ -48,6 +48,39 @@ Etherpad module exports following metrics :
- `etherpad_blank_pads_count` : Number of blank pads on the instance
Each metric have a `name` tag with the name of the instance.
### Mattermost
Mattermost module collects several metrics from the Mattermost API `/analytics/old` endpoint.
#### Configuration
To enable Mattermost module, you need to add a `mattermost` key to the `modules` object inside configuration JSON file. The value should be like this :
```json
"mattermost" : [
{
"url" : "https://my.mattermost.tld",
"user" : "admin_username",
"password" : "admin_password",
"name" : "instancename"
}
]
```
Pay attention that it is a **list** of objects (wich contains URL, credentials and name of your instance) in order to collect data from multiple Mattermost instances.
#### Metrics
Mattermost module exports following metrics :
- `mattermost_public_channels_count` : Number of public channels on the instance
- `mattermost_private_channels_count` : Number of private channels on the instance
- `mattermost_posts_count` : Number of posts on the instance
- `mattermost_users_count` : Number of users accounts on the instance
- `mattermost_teams_count` : Number of teams created on the instance
- `mattermost_daily_posts` : Number of posts created on a day
- `mattermost_daily_users` : Number of users that write a post on a day
Each metric have a `name` tag with the name of the instance.
## Creating a module
This bot can be easily extends by adding a module to gather metrics from a new service.
......
......@@ -11,6 +11,14 @@
"url" : "https://my.etherpad.tld",
"name" : "instancename"
}
],
"mattermost" : [
{
"url" : "https://my.mattermost.tld",
"user" : "admin_username",
"password" : "admin_password",
"name" : "instancename"
}
]
}
}
......@@ -10,6 +10,7 @@ import sys
from urllib.parse import urlparse
from influxdb import InfluxDBClient
from etherpad import EtherpadCollector
from mattermost import MattermostCollector
# Some constants
DIR_NAME = os.path.dirname(os.path.realpath(__file__))
......@@ -80,6 +81,12 @@ def main():
etherpad_data = etherpad.collect()
influx_client.write_points(etherpad_data, 'ms')
# Get Mattermost metrics and push to InfluxDB
if 'mattermost' in config['modules']:
mattermost = MattermostCollector(config['modules']['mattermost'])
mattermost_data = mattermost.collect()
influx_client.write_points(mattermost_data, 'ms')
if __name__ == "__main__":
main()
# coding=utf-8
"""Package to collect Mattermost metrics."""
from .mattermost import MattermostCollector
# coding=utf-8
"""Functions to export Mattermost metrics."""
# Libs
import json
import datetime
from urllib.parse import urlparse
from mattermostdriver import Driver
class MattermostCollector(object):
"""
MattermostCollector.
Collector for Mattermost stats.
"""
def __init__(self, config):
"""
Initialize a mattermost collector object.
:param config: Configuration for Mattermost module (list of instances)
"""
# Initialize list of instances connector
self.instances = []
for instance in config:
if 'url' not in instance or 'name' not in instance or 'user' not in instance or 'password' not in instance:
print('Incorrect instance configuration\n')
print(instance)
print('"mattermost" key on configuration file should be a list of object with "url", "user", "password" and "name" attributes')
continue
else:
# Parse the URL
o = urlparse(instance['url'])
if o.port is None:
if o.scheme == 'https':
mm_port = 443
elif o.scheme == 'http':
mm_port = 80
else:
print('Impossible to get Mattermost server port for ' + instance['url'])
continue
else:
mm_port = o.port
# Connect to mattermost
mat_api = Driver({
'url': o.hostname,
'login_id': instance['user'],
'password': instance['password'],
'scheme': o.scheme,
'port': mm_port
})
mat_api.login()
self.instances.append(
{
'conn': mat_api,
'config': instance
}
)
def collect(self):
"""
Get the analytics of mattermost instances and returns a list of InfluxDB points.
:returns: List of InfluxDB formatted objects
"""
metrics = []
# Get all instances stats
for instance in self.instances:
# Get current stats
data = self._get_stats(instance)
if data is None:
print('Unable to get stats from Mattermost instance ' + instance['config']['url'])
continue
# Get current miliseconds timestamp
current_timestamp = int(datetime.datetime.now().timestamp()*1000)
# Create metrics
metrics.append({
'measurement': 'mattermost_public_channels_count',
'tags': {
'name': instance['config']['name']
},
'time': current_timestamp,
'fields': {
'value': data['public_channels']
}
})
metrics.append({
'measurement': 'mattermost_private_channels_count',
'tags': {
'name': instance['config']['name']
},
'time': current_timestamp,
'fields': {
'value': data['private_channels']
}
})
metrics.append({
'measurement': 'mattermost_posts_count',
'tags': {
'name': instance['config']['name']
},
'time': current_timestamp,
'fields': {
'value': data['posts']
}
})
metrics.append({
'measurement': 'mattermost_users_count',
'tags': {
'name': instance['config']['name']
},
'time': current_timestamp,
'fields': {
'value': data['users']
}
})
metrics.append({
'measurement': 'mattermost_teams_count',
'tags': {
'name': instance['config']['name']
},
'time': current_timestamp,
'fields': {
'value': data['teams']
}
})
# Get daily stats
daily_data = self._get_daily_stats(instance)
if daily_data is None:
print('Unable to get daily stats from Mattermost instance ' + instance['config']['url'])
continue
# Create metrics
metrics.append({
'measurement': 'mattermost_daily_posts',
'tags': {
'name': instance['config']['name']
},
'time': daily_data['daily_posts']['timestamp'],
'fields': {
'value': daily_data['daily_posts']['value']
}
})
metrics.append({
'measurement': 'mattermost_daily_users',
'tags': {
'name': instance['config']['name']
},
'time': daily_data['daily_users_with_posts']['timestamp'],
'fields': {
'value': daily_data['daily_users_with_posts']['value']
}
})
return metrics
@classmethod
def _get_stats(cls, instance):
"""
Get stats for a Mattermost instance.
:param instance: Object with configuration and API connector for Mattermost instance
:returns: JSON data returned by Mattermost API
"""
# Get count stats
data = {}
try:
res = json.loads(instance['conn'].client.make_request('get', '/analytics/old', params={'name': 'standard'}).text)
except Exception as err:
print(err)
return None
# Extract values
data['public_channels'] = cls._get_value(res, 'channel_open_count')
data['private_channels'] = cls._get_value(res, 'channel_private_count')
data['posts'] = cls._get_value(res, 'post_count')
data['users'] = cls._get_value(res, 'unique_user_count')
data['teams'] = cls._get_value(res, 'team_count')
return data
@classmethod
def _get_daily_stats(cls, instance):
"""
Get daily stats for a Mattermost instance.
:param instance: Object with configuration and API connector for Mattermost instance
:returns: JSON data returned by Mattermost API
"""
# Get data
data = {}
try:
posts = json.loads(instance['conn'].client.make_request('get', '/analytics/old', params={'name': 'post_counts_day'}).text)
users = json.loads(instance['conn'].client.make_request('get', '/analytics/old', params={'name': 'user_counts_with_posts_day'}).text)
except Exception as err:
print(err)
return None
# Extract values
data['daily_posts'] = {
'value': posts[0]['value'],
'timestamp': int(datetime.datetime.strptime(posts[0]['name'], '%Y-%m-%d').timestamp()*1000)
}
data['daily_users_with_posts'] = {
'value': users[0]['value'],
'timestamp': int(datetime.datetime.strptime(users[0]['name'], '%Y-%m-%d').timestamp()*1000)
}
return data
@classmethod
def _get_value(cls, data, key):
"""
Get the value for a specific key in Mattermost analytics data
:param data: Mattermost data
:param key: Key to search
:returns: Value for the specific key
"""
try:
res = (i for i in data if i['name'] == key).__next__()
except StopIteration:
return None
return res['value']
influxdb==5.2.0
requests==2.18.4
mattermostdriver>=6.0.1
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment