Skip to content
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

Fmd telemetry gh pages update #456

Merged
merged 11 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
This project adheres to `Semantic Versioning <http://semver.org/>`_.
Please note that the changes before version 1.10.0 have not been documented.

v3.3.1
----------
Changed

- Telemetry now uses dynamic server-ip
- Removed survey
- FollowUp questions refactored

v3.3.0
----------
Changed
Expand Down
40 changes: 26 additions & 14 deletions docs/functionality.rst
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ Telemetry
The Dashboard is setup to be able to collect telemetric-data.
This data-collection can be toggled on and off under the "Configuration" route.

The collected data is released weekly at https://flask-dashboard.github.io/fmd-telemetry.

You can find detailed information about what and how data is collected below.

What:
Expand All @@ -356,7 +358,7 @@ What:

3. **Aggregated monitoring levels:** To determine the most frequently utilized monitoring level, we aggregate the levels set from each endpoint.

4. **Table size:** In order to determine how fast the data accumulates, we collect the size of the database and its tables.
4. **Version number:** In order to determine how often people update their dashboards, we collect the build number.

5. **Route visits:** Which routes you use in the dashboard.

Expand All @@ -368,19 +370,29 @@ This is most of the logic behind the telemetry:
.. code-block:: python

def post_to_back_if_telemetry_enabled(class_name='Endpoints', **kwargs):
"""
Function to send telemetry data to remote database
"""
if telemetry_config.telemetry_consent:
back4app_endpoint = f'https://parseapi.back4app.com/classes/{class_name}'

headers = telemetry_config.telemetry_headers
data = {'fmd_id': telemetry_config.fmd_user, 'session': telemetry_config.telemetry_session} # fmd_id is the random uuid of the user, session is amount of times app was initialized

for key, value in kwargs.items():
data[key] = value

requests.post(back4app_endpoint, json=data, headers=headers)
"""
Function to send data to server, with dynamic IP fetching.
If the IP cannot be fetched, the function will silently exit without sending data.
"""
if telemetry_config.telemetry_consent or class_name == 'FollowUp':
github_file_url = 'https://raw.githubusercontent.com/flask-dashboard/fmd-telemetry/master/ip_address'
parse_server_ip = fetch_ip_from_github(github_file_url)
if parse_server_ip is None:
return # Exit silently if no IP is fetched



parse_server_endpoint = f'http://{parse_server_ip}/parse/classes/{class_name}'
headers = telemetry_config.telemetry_headers
data = {'fmd_id': telemetry_config.fmd_user, 'session': telemetry_config.telemetry_session}
for key, value in kwargs.items():
data[key] = value

try:
response = requests.post(parse_server_endpoint, json=data, headers=headers, timeout=1)
return response
except requests.exceptions.ConnectionError as e:
return None


Need more information?
Expand Down
4 changes: 2 additions & 2 deletions flask_monitoringdashboard/constants.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.3.0",
"author": "Krzysztof Wielicki, Johannes Lind Christiansen",
"version": "3.3.1",
"author": "Johannes Lind Christiansen",
"email": "[email protected]"
}
5 changes: 2 additions & 3 deletions flask_monitoringdashboard/core/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def init_from(self, file=None, envvar=None, log_verbose=False):

class TelemetryConfig(object):
"""Configuration for the telemetry feature"""
# constants for defining survey and telemetry answers
# constants for defining telemetry answers
NOT_ANSWERED = 1
REJECTED = 2
ACCEPTED = 3
Expand All @@ -210,7 +210,6 @@ def __init__(self):
self.telemetry_consent = False
self.telemetry_session = 0
self.telemetry_headers = {
'X-Parse-Application-Id': '4nHPABwkHqOZzNrFduzNyKH8q7wmPFdOWvajfWU2',
'X-Parse-REST-API-Key': 'zjv0WLI2K3UvpfzrfG4sPA6EykYyzZM4KxQk07Hs',
'X-Parse-Application-Id': 'fmd-md',
'Content-Type': 'application/json'
}
55 changes: 45 additions & 10 deletions flask_monitoringdashboard/core/telemetry.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import datetime
import requests
import functools

from sqlalchemy import func
from sqlalchemy.exc import NoResultFound, MultipleResultsFound, SQLAlchemyError

from flask_monitoringdashboard import telemetry_config
from flask_monitoringdashboard.core.config import TelemetryConfig
from flask_monitoringdashboard.core.blueprints import get_blueprint
from flask_monitoringdashboard.core.utils import get_details
from flask_monitoringdashboard.database import TelemetryUser, Endpoint


Expand Down Expand Up @@ -49,13 +51,18 @@ def collect_general_telemetry_data(session, telemetry_user):
level_twos_count = counts_dict.get(2, 0)
level_threes_count = counts_dict.get(3, 0)

# Get details including the dashboard version
details = get_details(session)
dashboard_version = details['dashboard-version']

data = {'endpoints': no_of_endpoints,
'blueprints': no_of_blueprints,
'time_initialized': telemetry_user.last_initialized.strftime('%Y-%m-%d %H:%M:%S'),
'monitoring_0': level_zeros_count,
'monitoring_1': level_ones_count,
'monitoring_2': level_twos_count,
'monitoring_3': level_threes_count,
'dashboard_version': dashboard_version,
}

# post user data
Expand All @@ -78,13 +85,10 @@ def initialize_telemetry_session(session):
telemetry_user.last_initialized = datetime.datetime.utcnow()
session.commit()

# reset telemetry and survey prompt if declined in previous session
# reset telemetry if declined in previous session
if telemetry_user.monitoring_consent == TelemetryConfig.REJECTED:
telemetry_user.monitoring_consent = TelemetryConfig.NOT_ANSWERED
session.commit()
if telemetry_user.survey_filled == TelemetryConfig.REJECTED:
telemetry_user.survey_filled = TelemetryConfig.NOT_ANSWERED
session.commit()

# check if telemetry's been agreed on
telemetry_config.telemetry_consent = True if telemetry_user.monitoring_consent == TelemetryConfig.ACCEPTED else False
Expand All @@ -107,17 +111,48 @@ def initialize_telemetry_session(session):
session.rollback()


def post_to_back_if_telemetry_enabled(class_name='Endpoints', **kwargs):
@functools.cache
def fetch_ip_from_github(file_url):
"""
Function to send telemetry data to remote database
Fetches the IP address from a text file hosted on GitHub and caches the result.

Args:
file_url (str): URL to the raw version of the GitHub hosted text file containing the IP address.

Returns:
str: IP address and port as a string, or None if unable to fetch.
"""
if telemetry_config.telemetry_consent:
back4app_endpoint = f'https://parseapi.back4app.com/classes/{class_name}'
try:
response = requests.get(file_url)
response.raise_for_status() # Raises an HTTPError for bad responses
return response.text.strip() # Assuming the file contains the IP address and port in the format "IP:PORT"
except requests.RequestException:
return None


def post_to_back_if_telemetry_enabled(class_name='Endpoints', **kwargs):
"""
Function to send data to server, with dynamic IP fetching.
If the IP cannot be fetched, the function will silently exit without sending data.
"""
if telemetry_config.telemetry_consent or class_name == 'FollowUp':
github_file_url = 'https://raw.githubusercontent.com/flask-dashboard/fmd-telemetry/master/ip_address'
parse_server_ip = fetch_ip_from_github(github_file_url)
if parse_server_ip is None:
return # Exit silently if no IP is fetched



parse_server_endpoint = f'http://{parse_server_ip}/parse/classes/{class_name}'
headers = telemetry_config.telemetry_headers
data = {'fmd_id': telemetry_config.fmd_user, 'session': telemetry_config.telemetry_session}

for key, value in kwargs.items():
data[key] = value

requests.post(back4app_endpoint, json=data, headers=headers)
try:
response = requests.post(parse_server_endpoint, json=data, headers=headers, timeout=1)
return response
except requests.exceptions.ConnectionError as e:
return None


2 changes: 2 additions & 0 deletions flask_monitoringdashboard/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
get_date_of_first_request,
get_date_of_first_request_version,
)
from flask_monitoringdashboard import telemetry_config


def get_endpoint_details(session, endpoint_id):
Expand Down Expand Up @@ -57,6 +58,7 @@ def get_details(session):
'first-request': get_date_of_first_request(session),
'first-request-version': get_date_of_first_request_version(session, config.version),
'total-requests': count_total_requests(session),
'fmd-id': telemetry_config.fmd_user,
}


Expand Down
3 changes: 0 additions & 3 deletions flask_monitoringdashboard/database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ class TelemetryUser(Base):
last_initialized = Column(DateTime, default=datetime.datetime.utcnow)
"""Check when was the last time user accessed FMD"""

survey_filled = Column(Integer, default=1)
"""If user filled the survey 1 - not responded 2 - declined 3 - filled"""

monitoring_consent = Column(Integer, default=1)
"""If user agrees to share data 1 - not responded 2 - declined 3 - accepted"""

Expand Down
5 changes: 0 additions & 5 deletions flask_monitoringdashboard/frontend/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { DatabaseManagementController } from './controllers/databaseManagementCo
import { EndpointVersionIPController } from './controllers/endpointVersionIP';
import { EndpointVersionController } from "./controllers/endpointVersion";
import { MonitorLevelController } from "./controllers/monitorLevel";
import { SurveyController } from "./controllers/surveyController";
import { TelemetryController } from "./controllers/telemetryController";


Expand Down Expand Up @@ -85,10 +84,6 @@ app.controller('EndpointController', ['$scope', 'endpointService', EndpointContr
app.controller('PaginationController', ['$scope', 'paginationService', PaginationController]);
app.controller('ModalController', ['$scope', '$window', '$browser', 'modalService', ModalController]);

app.component('surveyComponent', {
templateUrl: 'static/pages/survey.html',
controller: SurveyController
});
app.component('telemetryComponent', {
templateUrl: 'static/pages/telemetry.html',
controller: TelemetryController
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,22 @@ export function TelemetryController($scope, $http, $window) {
};
$scope.customReason = '';

// Configuration for HTTP requests to Back4App
var config = {
headers: {
'X-Parse-Application-Id': '4nHPABwkHqOZzNrFduzNyKH8q7wmPFdOWvajfWU2',
'X-Parse-REST-API-Key': 'zjv0WLI2K3UvpfzrfG4sPA6EykYyzZM4KxQk07Hs',
'Content-Type': 'application/json'
}
};

// Function to submit follow-up feedback
$scope.submitFollowUp = function () {
$scope.followUpShow = false;

var feedback = [];
for (var key in $scope.reasons) {
if ($scope.reasons[key]) {
if (key === 'other') {
feedback.push(key);
if ($scope.customReason.trim() !== '') {
feedback.push({ other: $scope.customReason });
}
if (key === 'other' && $scope.customReason.trim() !== '') {
feedback.push({ key: 'other', other_reason: $scope.customReason });
} else {
feedback.push(key);
feedback.push({ key: key });
}
}
}

$http.post('https://parseapi.back4app.com/classes/FollowUp', { reasons: feedback }, config)
$http.post('/dashboard/telemetry/submit_follow_up', { feedback: feedback })
.then(function (response) {
}, function (error) {
console.error('Error sending feedback:', error);
Expand Down
14 changes: 0 additions & 14 deletions flask_monitoringdashboard/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,6 @@ progress {
margin-top: calc(-1 * var(--bs-gutter-y));
margin-right: calc(-0.5 * var(--bs-gutter-x));
margin-left: calc(-0.5 * var(--bs-gutter-x));
overflow: auto;
}
.row > * {
flex-shrink: 0;
Expand Down Expand Up @@ -4315,13 +4314,6 @@ textarea.form-control-lg {
list-style: none;
}

.navbar-btn {
display: none;
position: absolute;
right: 11px;
top: 13px;
}

.nav-link {
display: block;
padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);
Expand Down Expand Up @@ -6193,12 +6185,6 @@ textarea.form-control-lg {
}
}
@media (max-width: 991.98px) {


.navbar-btn {
display: block !important;
}

.modal-fullscreen-lg-down {
width: 100vw;
max-width: none;
Expand Down
15 changes: 2 additions & 13 deletions flask_monitoringdashboard/static/js/app.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions flask_monitoringdashboard/static/pages/configuration.html
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ <h4>Deployment details</h4>
<td><b>Total amount of monitored requests</b></td>
<td>{{ details['total-requests'] | number }}</td>
</tr>

<tr>
<td><b>fmd_id</b></td>
<td>{{ details['fmd-id'] }}</td>
</tr>
</table>
</div>
</div>
Expand Down
Loading
Loading