Create /logs/ api endpoint
This commit is contained in:
parent
43f578d311
commit
8ce22eca95
3 changed files with 156 additions and 146 deletions
|
|
@ -191,6 +191,17 @@ app.get('/api/logs/:deviceId', (req, res, next) => {
|
||||||
.catch(next)
|
.catch(next)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get('/api/logs', (req, res, next) => {
|
||||||
|
return machineLoader.getMachines()
|
||||||
|
.then(machines => {
|
||||||
|
const firstMachine = _.first(machines)
|
||||||
|
if (!firstMachine) return res.status(404).send({Error: 'No machines'})
|
||||||
|
return logs.getMachineLogs(firstMachine.deviceId)
|
||||||
|
.then(r => res.send(r))
|
||||||
|
})
|
||||||
|
.catch(next)
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endpoint for patching customer's data
|
* Endpoint for patching customer's data
|
||||||
*
|
*
|
||||||
|
|
|
||||||
97
lib/logs.js
97
lib/logs.js
|
|
@ -1,10 +1,24 @@
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const db = require('./db')
|
const db = require('./db')
|
||||||
const machineLoader = require('./machine-loader')
|
const pgp = require('pg-promise')()
|
||||||
|
|
||||||
|
const settingsLoader = require('./settings-loader')
|
||||||
|
const configManager = require('./config-manager')
|
||||||
|
|
||||||
const NUM_RESULTS = 1000
|
const NUM_RESULTS = 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latest log's timestamp
|
||||||
|
*
|
||||||
|
* @name getLastSeen
|
||||||
|
* @function
|
||||||
|
* @async
|
||||||
|
*
|
||||||
|
* @param {string} deviceId Machine id to get the last timestamp for
|
||||||
|
*
|
||||||
|
* @returns {date} Last timestamp
|
||||||
|
*/
|
||||||
function getLastSeen (deviceId) {
|
function getLastSeen (deviceId) {
|
||||||
const sql = `select timestamp from logs
|
const sql = `select timestamp from logs
|
||||||
where device_id=$1
|
where device_id=$1
|
||||||
|
|
@ -13,27 +27,35 @@ function getLastSeen (deviceId) {
|
||||||
.then(log => log ? log.timestamp : null)
|
.then(log => log ? log.timestamp : null)
|
||||||
}
|
}
|
||||||
|
|
||||||
function insert (log) {
|
/**
|
||||||
console.log('inserting', log)
|
* Update logs in db
|
||||||
const sql = `insert into logs
|
*
|
||||||
(id, device_id, log_level, timestamp, message) values
|
* @name update
|
||||||
($1, $2, $3, $4, $5) on conflict do nothing`
|
* @function
|
||||||
return db.oneOrNone(sql, [log.id, log.deviceId, log.logLevel, log.timestamp, log.message])
|
* @async
|
||||||
}
|
*
|
||||||
|
* @param {string} deviceId Machine Id to which logs belong to
|
||||||
|
* @param {array} logLines Logs to be saved
|
||||||
|
*
|
||||||
|
* @returns {null}
|
||||||
|
*/
|
||||||
function update (deviceId, logLines) {
|
function update (deviceId, logLines) {
|
||||||
// Prepare logs to update
|
const cs = new pgp.helpers.ColumnSet([
|
||||||
|
'id', 'device_id', 'log_level', 'timestamp', 'message'],
|
||||||
|
{table: 'logs'})
|
||||||
|
|
||||||
const logs = _.map(log => {
|
const logs = _.map(log => {
|
||||||
return {
|
const formatted = {
|
||||||
id: log.id,
|
id: log.id,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
message: log.msg,
|
message: log.msg,
|
||||||
logLevel: log.level,
|
logLevel: log.level,
|
||||||
timestamp: log.timestamp
|
timestamp: log.timestamp
|
||||||
}
|
}
|
||||||
|
return _.mapKeys(_.snakeCase, formatted)
|
||||||
}, logLines)
|
}, logLines)
|
||||||
// Batch save logs
|
const sql = pgp.helpers.insert(logs, cs)
|
||||||
return Promise.all(_.map(insert, _.compact(logs)))
|
return db.none(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,51 +69,32 @@ function update (deviceId, logLines) {
|
||||||
* @returns {array} Array of logs for the requested machinej
|
* @returns {array} Array of logs for the requested machinej
|
||||||
*/
|
*/
|
||||||
function getMachineLogs (deviceId) {
|
function getMachineLogs (deviceId) {
|
||||||
const sql = `select * from logs
|
const sql = `select id, log_level, timestamp, message from logs
|
||||||
where device_id=$1
|
where device_id=$1
|
||||||
order by timestamp desc limit $2`
|
order by timestamp desc limit $2`
|
||||||
return db.any(sql, [ deviceId, NUM_RESULTS ])
|
return Promise.all([db.any(sql, [ deviceId, NUM_RESULTS ]), getMachineName(deviceId)])
|
||||||
.then(_.map(camelize))
|
.then(([logs, machineName]) => ({
|
||||||
.then(logs => {
|
logs: _.map(_.mapKeys(_.camelCase), logs),
|
||||||
return getMachineById(deviceId)
|
currentMachine: {deviceId, name: machineName}
|
||||||
.then(currentMachine => {
|
}))
|
||||||
return {
|
|
||||||
logs,
|
|
||||||
currentMachine
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find machine by id
|
* Given the machine id, get the machine name
|
||||||
*
|
*
|
||||||
* @name getMachineById
|
* @name getMachineName
|
||||||
* @function
|
* @function
|
||||||
* @async
|
* @async
|
||||||
*
|
*
|
||||||
* @param {string} deviceId machine's id
|
* @param {string} machineId machine id
|
||||||
*
|
* @returns {string} machine name
|
||||||
* @returns {object} Found machine
|
|
||||||
*/
|
*/
|
||||||
function getMachineById (deviceId) {
|
function getMachineName (machineId) {
|
||||||
return machineLoader.getMachineNames().then(names => {
|
return settingsLoader.loadRecentConfig()
|
||||||
return _.find({deviceId}, names)
|
.then(config => {
|
||||||
|
const machineScoped = configManager.machineScoped(machineId, config)
|
||||||
|
return machineScoped.machineName
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Camelize log fields
|
|
||||||
* Note: return null if log is undefined
|
|
||||||
*
|
|
||||||
* @name camelize
|
|
||||||
* @function
|
|
||||||
*
|
|
||||||
* @param {object} log Log with snake_case fields
|
|
||||||
* @returns {object} Camelized Log object
|
|
||||||
*/
|
|
||||||
function camelize (log) {
|
|
||||||
return log ? _.mapKeys(_.camelCase, log) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getMachineLogs, update, getLastSeen }
|
module.exports = { getMachineLogs, update, getLastSeen }
|
||||||
|
|
|
||||||
194
public/elm.js
194
public/elm.js
|
|
@ -34135,9 +34135,9 @@ var _user$project$Logs_Types$Machine = F2(
|
||||||
function (a, b) {
|
function (a, b) {
|
||||||
return {deviceId: a, name: b};
|
return {deviceId: a, name: b};
|
||||||
});
|
});
|
||||||
var _user$project$Logs_Types$Log = F5(
|
var _user$project$Logs_Types$Log = F4(
|
||||||
function (a, b, c, d, e) {
|
function (a, b, c, d) {
|
||||||
return {id: a, deviceId: b, timestamp: c, logLevel: d, message: e};
|
return {id: a, timestamp: b, logLevel: c, message: d};
|
||||||
});
|
});
|
||||||
var _user$project$Logs_Types$Logs = F2(
|
var _user$project$Logs_Types$Logs = F2(
|
||||||
function (a, b) {
|
function (a, b) {
|
||||||
|
|
@ -35547,13 +35547,9 @@ var _user$project$Logs_Decoder$logDecoder = A3(
|
||||||
_elm_lang$core$Json_Decode$nullable(_elm_community$json_extra$Json_Decode_Extra$date),
|
_elm_lang$core$Json_Decode$nullable(_elm_community$json_extra$Json_Decode_Extra$date),
|
||||||
A3(
|
A3(
|
||||||
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
|
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
|
||||||
'deviceId',
|
'id',
|
||||||
_elm_lang$core$Json_Decode$nullable(_elm_lang$core$Json_Decode$string),
|
_elm_lang$core$Json_Decode$string,
|
||||||
A3(
|
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Logs_Types$Log)))));
|
||||||
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
|
|
||||||
'id',
|
|
||||||
_elm_lang$core$Json_Decode$string,
|
|
||||||
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Logs_Types$Log))))));
|
|
||||||
var _user$project$Logs_Decoder$logsDecoder = A3(
|
var _user$project$Logs_Decoder$logsDecoder = A3(
|
||||||
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
|
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
|
||||||
'currentMachine',
|
'currentMachine',
|
||||||
|
|
@ -35696,45 +35692,45 @@ var _user$project$Logs_View$logsView = function (logs) {
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: A2(
|
_0: A2(
|
||||||
_elm_lang$html$Html$h2,
|
_elm_lang$html$Html$table,
|
||||||
{ctor: '[]'},
|
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _elm_lang$html$Html$text('Logs'),
|
_0: _user$project$Css_Admin$class(
|
||||||
|
{
|
||||||
|
ctor: '::',
|
||||||
|
_0: _user$project$Css_Classes$TxTable,
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}),
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}),
|
},
|
||||||
_1: {
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: A2(
|
_0: A2(
|
||||||
_elm_lang$html$Html$table,
|
_elm_lang$html$Html$thead,
|
||||||
{
|
{ctor: '[]'},
|
||||||
ctor: '::',
|
{
|
||||||
_0: _user$project$Css_Admin$class(
|
ctor: '::',
|
||||||
{
|
_0: A2(
|
||||||
ctor: '::',
|
_elm_lang$html$Html$tr,
|
||||||
_0: _user$project$Css_Classes$TxTable,
|
{ctor: '[]'},
|
||||||
_1: {ctor: '[]'}
|
{
|
||||||
}),
|
ctor: '::',
|
||||||
_1: {ctor: '[]'}
|
_0: A2(
|
||||||
},
|
_elm_lang$html$Html$td,
|
||||||
{
|
{ctor: '[]'},
|
||||||
ctor: '::',
|
{
|
||||||
_0: A2(
|
ctor: '::',
|
||||||
_elm_lang$html$Html$thead,
|
_0: _elm_lang$html$Html$text('Date'),
|
||||||
{ctor: '[]'},
|
_1: {ctor: '[]'}
|
||||||
{
|
}),
|
||||||
ctor: '::',
|
_1: {
|
||||||
_0: A2(
|
|
||||||
_elm_lang$html$Html$tr,
|
|
||||||
{ctor: '[]'},
|
|
||||||
{
|
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: A2(
|
_0: A2(
|
||||||
_elm_lang$html$Html$td,
|
_elm_lang$html$Html$td,
|
||||||
{ctor: '[]'},
|
{ctor: '[]'},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _elm_lang$html$Html$text('Date'),
|
_0: _elm_lang$html$Html$text('Level'),
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}),
|
}),
|
||||||
_1: {
|
_1: {
|
||||||
|
|
@ -35744,36 +35740,25 @@ var _user$project$Logs_View$logsView = function (logs) {
|
||||||
{ctor: '[]'},
|
{ctor: '[]'},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _elm_lang$html$Html$text('Level'),
|
_0: _elm_lang$html$Html$text('Message'),
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}),
|
}),
|
||||||
_1: {
|
_1: {ctor: '[]'}
|
||||||
ctor: '::',
|
|
||||||
_0: A2(
|
|
||||||
_elm_lang$html$Html$td,
|
|
||||||
{ctor: '[]'},
|
|
||||||
{
|
|
||||||
ctor: '::',
|
|
||||||
_0: _elm_lang$html$Html$text('Message'),
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
}),
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
_1: {ctor: '[]'}
|
}),
|
||||||
}),
|
|
||||||
_1: {
|
|
||||||
ctor: '::',
|
|
||||||
_0: A2(
|
|
||||||
_elm_lang$html$Html$tbody,
|
|
||||||
{ctor: '[]'},
|
|
||||||
A2(_elm_lang$core$List$map, _user$project$Logs_View$rowView, logs.logs)),
|
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}
|
}),
|
||||||
}),
|
_1: {
|
||||||
_1: {ctor: '[]'}
|
ctor: '::',
|
||||||
}
|
_0: A2(
|
||||||
|
_elm_lang$html$Html$tbody,
|
||||||
|
{ctor: '[]'},
|
||||||
|
A2(_elm_lang$core$List$map, _user$project$Logs_View$rowView, logs.logs)),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var _user$project$Logs_View$logs = function (model) {
|
var _user$project$Logs_View$logs = function (model) {
|
||||||
|
|
@ -35786,7 +35771,7 @@ var _user$project$Logs_View$logs = function (model) {
|
||||||
{ctor: '[]'});
|
{ctor: '[]'});
|
||||||
case 'Loading':
|
case 'Loading':
|
||||||
return A2(
|
return A2(
|
||||||
_elm_lang$html$Html$h2,
|
_elm_lang$html$Html$div,
|
||||||
{ctor: '[]'},
|
{ctor: '[]'},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
|
|
@ -35884,37 +35869,26 @@ var _user$project$Logs_View$machinesView = function (machines) {
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: A2(
|
_0: A2(
|
||||||
_elm_lang$html$Html$h2,
|
_elm_lang$html$Html$div,
|
||||||
{ctor: '[]'},
|
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _elm_lang$html$Html$text('Machines'),
|
_0: _user$project$Css_Admin$class(
|
||||||
|
{
|
||||||
|
ctor: '::',
|
||||||
|
_0: _user$project$Css_Classes$TxTable,
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ctor: '::',
|
||||||
|
_0: A2(
|
||||||
|
_elm_lang$html$Html$ul,
|
||||||
|
{ctor: '[]'},
|
||||||
|
A2(_elm_lang$core$List$map, _user$project$Logs_View$machineItemView, machines)),
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}),
|
}),
|
||||||
_1: {
|
_1: {ctor: '[]'}
|
||||||
ctor: '::',
|
|
||||||
_0: A2(
|
|
||||||
_elm_lang$html$Html$div,
|
|
||||||
{
|
|
||||||
ctor: '::',
|
|
||||||
_0: _user$project$Css_Admin$class(
|
|
||||||
{
|
|
||||||
ctor: '::',
|
|
||||||
_0: _user$project$Css_Classes$TxTable,
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
}),
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ctor: '::',
|
|
||||||
_0: A2(
|
|
||||||
_elm_lang$html$Html$ul,
|
|
||||||
{ctor: '[]'},
|
|
||||||
A2(_elm_lang$core$List$map, _user$project$Logs_View$machineItemView, machines)),
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
}),
|
|
||||||
_1: {ctor: '[]'}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var _user$project$Logs_View$machines = function (model) {
|
var _user$project$Logs_View$machines = function (model) {
|
||||||
|
|
@ -35927,7 +35901,7 @@ var _user$project$Logs_View$machines = function (model) {
|
||||||
{ctor: '[]'});
|
{ctor: '[]'});
|
||||||
case 'Loading':
|
case 'Loading':
|
||||||
return A2(
|
return A2(
|
||||||
_elm_lang$html$Html$h2,
|
_elm_lang$html$Html$div,
|
||||||
{ctor: '[]'},
|
{ctor: '[]'},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
|
|
@ -35999,8 +35973,19 @@ var _user$project$Logs_View$view = function (model) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _user$project$Logs_View$machines(model),
|
_0: A2(
|
||||||
_1: {ctor: '[]'}
|
_elm_lang$html$Html$h2,
|
||||||
|
{ctor: '[]'},
|
||||||
|
{
|
||||||
|
ctor: '::',
|
||||||
|
_0: _elm_lang$html$Html$text('Machines'),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}),
|
||||||
|
_1: {
|
||||||
|
ctor: '::',
|
||||||
|
_0: _user$project$Logs_View$machines(model),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
_1: {
|
_1: {
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
|
|
@ -36018,8 +36003,19 @@ var _user$project$Logs_View$view = function (model) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: _user$project$Logs_View$logs(model),
|
_0: A2(
|
||||||
_1: {ctor: '[]'}
|
_elm_lang$html$Html$h2,
|
||||||
|
{ctor: '[]'},
|
||||||
|
{
|
||||||
|
ctor: '::',
|
||||||
|
_0: _elm_lang$html$Html$text('Logs'),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}),
|
||||||
|
_1: {
|
||||||
|
ctor: '::',
|
||||||
|
_0: _user$project$Logs_View$logs(model),
|
||||||
|
_1: {ctor: '[]'}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue