Add basic player restart alerts

This commit is contained in:
Matthew Stratford 2021-09-21 22:49:05 +01:00
parent f1e04c3d8a
commit 7dc0facf73
2 changed files with 97 additions and 1 deletions

93
alerts/player.py Normal file
View file

@ -0,0 +1,93 @@
# Any alerts produced by the player.py instances.
import json
from typing import Any, Dict, List, Optional
from datetime import datetime, timedelta
from helpers.os_environment import resolve_external_file_path
from helpers.alert_manager import AlertProvider
from baps_types.alert import CRITICAL, WARNING, Alert
MODULE = "Player" # This should match the log file, so the UI will link to the logs page.
class PlayerAlertProvider(AlertProvider):
_server_state: Dict[str, Any]
_states: List[Optional[Dict[str,Any]]] = []
_player_count: int
def __init__(self):
# Player count only changes after server restart, may as well just load this once.
with open(resolve_external_file_path("state/BAPSicleServer.json")) as file:
self._server_state = json.loads(file.read())
self._player_count = int(self._server_state["num_channels"])
self._states = [None] * self._player_count
# To simplify monitoring (and allow detection of things going super weird), we are going to read from the state file to work out the alerts.
def get_alerts(self):
for channel in range(self._player_count):
with open(resolve_external_file_path("state/Player{}.json".format(channel))) as file:
self._states[channel] = json.loads(file.read())
funcs = [self._channel_count, self._initialised, self._start_time]
alerts: List[Alert] = []
for func in funcs:
func_alerts = func()
if func_alerts:
alerts.extend(func_alerts)
return alerts
def _channel_count(self):
if self._player_count <= 0:
return [Alert({
"start_time": -1, # Now
"id": "no_channels",
"title": "There are no players configured.",
"description": "The number of channels configured is {}. Please set to at least 1 on the 'Server Config' page.".format(self._player_count),
"module": MODULE+"Handler",
"severity": CRITICAL
})]
def _initialised(self):
alerts: List[Alert] = []
for channel in range(self._player_count):
if self._states[channel] and not self._states[channel]["initialised"]:
alerts.append(Alert({
"start_time": -1, # Now
"id": "player_{}_not_initialised".format(channel),
"title": "Player {} is not initialised.".format(channel),
"description": "This typically means the player channel was not able find the configured sound output on the system. Please check the 'Player Config' and Player logs to determine the cause.",
"module": MODULE+str(channel),
"severity": CRITICAL
}))
return alerts
def _start_time(self):
server_start_time = self._server_state["start_time"]
server_start_time = datetime.fromtimestamp(server_start_time)
delta = timedelta(
seconds=30,
)
alerts: List[Alert] = []
for channel in range(self._player_count):
start_time = self._states[channel]["start_time"]
start_time = datetime.fromtimestamp(start_time)
if (start_time > server_start_time + delta):
alerts.append(Alert({
"start_time": -1,
"id": "player_{}_restarted".format(channel),
"title": "Player {} restarted after the server started.".format(channel),
"description":
"""Player {} last restarted at {}, after the server first started at {}, suggesting a failure.
This likely means there was an unhandled exception in the player code, causing the server to restart the player.
Please check player logs to investigate the cause. Please restart the server to clear this warning."""
.format(channel, str(start_time).rsplit(".",1)[0], str(server_start_time).rsplit(".",1)[0]),
"module": MODULE+str(channel),
"severity": WARNING
}))
return alerts

View file

@ -35,6 +35,7 @@ from pygame import mixer
from mutagen.mp3 import MP3 from mutagen.mp3 import MP3
from syncer import sync from syncer import sync
from threading import Timer from threading import Timer
from datetime import datetime
from helpers.normalisation import get_normalised_filename_if_available from helpers.normalisation import get_normalised_filename_if_available
from helpers.myradio_api import MyRadioAPI from helpers.myradio_api import MyRadioAPI
@ -969,7 +970,7 @@ class Player:
self.out_q = out_q self.out_q = out_q
self.logger = LoggingManager( self.logger = LoggingManager(
"Player" + str(channel), debug=package.build_beta) "Player" + str(channel), debug=package.BETA)
self.api = MyRadioAPI(self.logger, server_state) self.api = MyRadioAPI(self.logger, server_state)
@ -980,6 +981,8 @@ class Player:
self.__rate_limited_params, self.__rate_limited_params,
) )
self.state.update("start_time", datetime.now().timestamp())
self.state.add_callback(self._send_status) self.state.add_callback(self._send_status)
self.state.update("channel", channel) self.state.update("channel", channel)