Skip to content

Commit

Permalink
lestarch: fixing GDS logs to load only when selected
Browse files Browse the repository at this point in the history
  • Loading branch information
LeStarch committed Aug 2, 2021
1 parent 6b72162 commit d874ad6
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 58 deletions.
7 changes: 6 additions & 1 deletion src/fprime_gds/flask/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,15 @@ def construct_app():
# Optionally serve log files
if app.config["SERVE_LOGS"]:
api.add_resource(
fprime_gds.flask.logs.FlaskLogger,
fprime_gds.flask.logs.LogList,
"/logdata",
resource_class_args=[app.config["LOG_DIR"]],
)
api.add_resource(
fprime_gds.flask.logs.LogFile,
"/logdata/<name>",
resource_class_args=[app.config["LOG_DIR"]],
)
return app, api


Expand Down
36 changes: 26 additions & 10 deletions src/fprime_gds/flask/logs.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
####
#
# Handles GDS logs in a lazy-loading way
####
import os
import flask_restful
import flask_restful.reqparse


class FlaskLogger(flask_restful.Resource):
class LogList(flask_restful.Resource):
""" A list of log files as produced by the GDS. """

def __init__(self, logdir):
"""
Constructor used to setup the log directory.
:param logdir: log directory to search for logs
"""
self.logdir = logdir

def get(self):
""" Returns a list of log files that are available. """
logs = {}
listing = os.listdir(self.logdir)
return {"logs": [name for name in listing if name.endswith(".log")]}


class LogFile(flask_restful.Resource):
"""
Command dictionary endpoint. Will return dictionary when hit with a GET.
"""
Expand All @@ -19,16 +37,14 @@ def __init__(self, logdir):
"""
self.logdir = logdir

def get(self):
def get(self, name):
"""
Returns the logdir.
"""
logs = {}
listing = os.listdir(self.logdir)
for path in [path for path in listing if path.endswith(".log")]:
full_path = os.path.join(self.logdir, path)
offset = 0
with open(full_path) as file_handle:
file_handle.seek(offset)
logs[path] = file_handle.read()
full_path = os.path.join(self.logdir, name)
offset = 0
with open(full_path) as file_handle:
file_handle.seek(offset)
logs[name] = file_handle.read()
return logs
22 changes: 0 additions & 22 deletions src/fprime_gds/flask/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -124,29 +124,7 @@
</v-runtime-template>
</div>
</template>
<!--
Logs:

Logs template used to display log information from the system. Contains a selectable list of logs and a
panel that displays the raw text, with light highlighting.
-->
<template id="logs-template">
<div class="fp-flex-repeater">
<div class="fp-flex-header">
<label for="logselect">Available Logs:</label>
<v-select id="logselect"
:clearable="false" :searchable="true"
:filterable="true" :options="options"
v-model="selected">
</v-select>
</div>
<div class="fp-scroll-container">
<div class="fp-scrollable fp-color-logging">
<pre><code>{{logs[selected]}}</code></pre>
</div>
</div>
</div>
</template>
<!--
Command History:
Expand Down
5 changes: 4 additions & 1 deletion src/fprime_gds/flask/static/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ export let config = {
// Set the icon for the condition when there is a data-flow error
dataErrorIcon: "/img/error.svg",
// Data polling interval in milliseconds
dataPollIntervalMs: 1000
dataPollIntervalsMs: {
channels: 500,
default: 1000
}
};
18 changes: 3 additions & 15 deletions src/fprime_gds/flask/static/js/datastore.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,16 @@ import {_loader} from "./loader.js";
export class DataStore {

constructor() {
this.loggers = [];
// Activity timeout for checking spacecraft health and "the orb" (ours, not Keynes')
this.active = [false, false];
this.active_timeout = null;

// Data stores used to store all data supplied to the system
this.events = [];
this.command_history = [];
this.latest_channels = [];
this.channels = {};
this.commands = {};
this.logs ={"": ""};
this.logs =[];

// File data stores used for file handling
this.downfiles = [];
Expand Down Expand Up @@ -70,16 +68,11 @@ export class DataStore {
_loader.registerPoller("channels", this.updateChannels.bind(this));
_loader.registerPoller("events", this.updateEvents.bind(this));
_loader.registerPoller("commands", this.updateCommandHistory.bind(this));
//_loader.registerPoller("logdata", this.updateLogs.bind(this));
_loader.registerPoller("logdata", this.updateLogs.bind(this));
_loader.registerPoller("upfiles", this.updateUpfiles.bind(this));
_loader.registerPoller("downfiles", this.updateDownfiles.bind(this));
}

registerLogHandler(item) {
this.loggers.push(item);
return this.logs;
}

registerActiveHandler(item) {
this.actives.push(item);
return [false, false];
Expand Down Expand Up @@ -115,10 +108,7 @@ export class DataStore {
}

updateLogs(log_data) {
this.logs = log_data;
for (let i = 0; i < this.loggers.length; i++) {
this.loggers[i].update();
}
this.logs.splice(0, this.logs.length, ...log_data.logs);
}

updateUpfiles(data) {
Expand All @@ -140,8 +130,6 @@ export class DataStore {
this.active.splice(index, 1, true);
clearTimeout(this.active_timeout);
this.active_timeout = setTimeout(() => _self.active.splice(index, 1, false), timeout);
} else {
this.active.splice(index, 1, false);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/fprime_gds/flask/static/js/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ class Loader {
if ("interval" in this.endpoints[endpoint]) {
clearInterval(this.endpoints[endpoint]["interval"]);
}
this.endpoints[endpoint]["interval"] = setInterval(handler, config["dataPollIntervalMs"]);
let interval = config.dataPollIntervalsMs[endpoint] || config.dataPollIntervalsMs.default || 1000;
this.endpoints[endpoint]["interval"] = setInterval(handler, interval);
handler();
}

Expand Down
46 changes: 39 additions & 7 deletions src/fprime_gds/flask/static/js/vue-support/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,64 @@
// Setup component for select
import "../../third-party/js/vue-select.js"
import {_datastore} from "../datastore.js"
import {_loader} from "../loader.js";


/**
* Logs template used to display log information from the system. Contains a selectable list of logs and a
panel that displays the raw text, with light highlighting.
*/
let template = `
<div class="fp-flex-repeater">
<div class="fp-flex-header">
<label for="logselect">Available Logs:</label>
<v-select id="logselect"
:clearable="true" :searchable="true"
:filterable="true" :options="options"
v-model="selected">
</v-select>
</div>
<div class="fp-scroll-container">
<div class="fp-scrollable fp-color-logging">
<pre><code>{{ text }}</code></pre>
</div>
</div>
</div>
`;


// Must provide v-select
Vue.component('v-select', VueSelect.VueSelect);

Vue.component("logging", {
template: "#logs-template",
data: function() { return {"selected": "", "logs": _datastore.registerLogHandler(this)};},
template: template,
data() {return {"selected": "", "logs": _datastore.logs, text: ""}},
mounted() {
setInterval(this.update, 1000); // Grab log updates once a second
},
computed:{
/**
* Computes the appropriate log files available.
* @return {string[]}
*/
options: function () {
let kets = Object.keys(this.logs);
return kets;
return this.logs;
}
},
methods: {
/**
* Updates the log data such that new logs can be displayed.
*/
update() {
for (let key in _datastore.logs) {
this.$set(this.logs, key, _datastore.logs[key]);
let _self = this;
if (this.selected === "") {
return;
}
this.$el.scrollTop = this.$el.scrollHeight;
_loader.load("/logdata/" + this.selected, "GET").then(
(result) => {
_self.text = result[_self.selected];
this.$el.scrollTop = this.$el.scrollHeight
}).catch((result) => {_self.text = "[ERROR] "+ result});
}
}
});
2 changes: 1 addition & 1 deletion src/fprime_gds/flask/static/js/vue-support/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function filter(items, matching, ifun) {
* @param time: time object in fprime time format
* @return {Date}: Javascript date object
*/
function timeToDate(time) {
export function timeToDate(time) {
let date = new Date((time.seconds * 1000) + (time.microseconds/1000));
return date;
}
Expand Down

0 comments on commit d874ad6

Please sign in to comment.